IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 探索数据结构与算法——如何运用异或,二分解题 -> 正文阅读

[数据结构与算法]探索数据结构与算法——如何运用异或,二分解题

目录

📔 前言

📘 异或

📑 例题引入

📜 练习巩固

📒 二分法

📕 例题引入

📰 练习巩固

?📰 总结:


📔 前言

数据结构与算法如今在工作面试中占很高的比重,为了学好算法,大多数人都会去看各种书籍与视频,然后去做题,以做leetcode为例,没学算法前,你可能可以做些简单题,中等题也会一部分,学过数据结构与算法后,你可能发现自己会的中等题变多了,但依然有许多题无从下手,想暴力可时间过不了,此类情况就是无法将所学结合起来,没想到能用学过的方法解题,接下来,我们就来通过题目,剖析异或与二分。

📘 异或

异或作为位运算的一种,其运算方法为:相同(1与1,0与0)为0,相异为1

📑 例题引入

交换两个整数a,b 不能创建其他变量

void swap(int *a,int *b)
{
 a^=b;
 b^=a;
 a^=b;
}

代码很简单,异或就能解决,那么我们先来剖析一下怎么实现的

首先,我们要了解一些知识:异或是满足交换律和结合律的即:

a^b==b^a;
(a^b)^c==a^(b^c);

然后,一个数异或0为这个数本身,异或自生则为0

a^0==a;
a^a==0;

这个本身指的不是数字相同,而是开辟的空间相同,故只要开辟的空间不一样,那么异或后就不会为0.

a^=b ——> a=a^b

b^=a——>b=b^a^b——>b=b^b^a=a

a^=b——>a^b^a——>a^a^b——>=b

以上便是交换的

过程,了解了这些知识,接下来我们便可以做更多类型的题

📜 练习巩固

136. 只出现一次的数字

给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。

说明:

你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?

示例 1:

输入: [2,2,1]
输出: 1

示例?2:

输入: [4,1,2,1,2]
输出: 4

?此题用异或计算非常简单,异或数组,因为交换律二次的异或后都为0,只剩出现一次的数,奇偶也是此方法,如一个数出现了奇数次,其他数出现了偶数次

int singleNumber(int* nums, int numsSize){
    int j=0;
for(int i=0;i<numsSize;i++)
{
 j^=nums[i];
}
return j;
}

260. 只出现一次的数字 III

给定一个整数数组?nums,其中恰好有两个元素只出现一次,其余所有元素均出现两次。 找出只出现一次的那两个元素。你可以按?任意顺序?返回答案。

进阶:你的算法应该具有线性时间复杂度。你能否仅使用常数空间复杂度来实现?

示例 1:

输入:nums = [1,2,1,3,2,5]
输出:[3,5]
解释:[5, 3] 也是有效的答案。

示例 2:

输入:nums = [-1,0]
输出:[-1,0]

示例 3:

输入:nums = [0,1]
输出:[1,0]
/**
 * Note: The returned array must be malloced, assume caller calls free().
 */
int* singleNumber(int* nums, int numsSize, int* returnSize){
long long num=0;long long num1=0;
int *arr=(int*)malloc(sizeof(int)*2);
for(int i=0;i<numsSize;++i)
{
    num^=nums[i];
}
long long num2=num;
num1=num&(~num+1);
for(int i=0;i<numsSize;++i)
{
    if((num1&nums[i])!=0)
    num^=nums[i];
}
num2^=num;
arr[0]=num;arr[1]=num2;
*returnSize=2;
return arr;
}

?要解决此题当然也是通过异或数组,接下来,我们通过代码来剖析方法:

前半段代码异或数组

for(int i=0;i<numsSize;++i)
{
    num^=nums[i];
}

此时得到的是两个出现一次元素的异或且num肯定大于0,接下来这行便有意思了

long long num2=num;
num1=num&(~num+1);

这行什么意思呢?我们画图理解:

?知道这个可能部分人就能想出来为什么要这么做了,不知道也没关系,我们继续剖析

for(int i=0;i<numsSize;++i)
{
    if((num1&nums[i])!=0)
    num^=nums[i];
}

这段代码其实是在做区分,前边说了,两个出现一次的数异或其结果必不是0,那么,我们便找到其最右边的一(上一步),把整个数组分为两部分:一部分是这位上含一的,一部分是不含一的

📒 二分法

? 相信二分法大家早就很熟悉了,学习编程语言的时候我们就学习过二分法,但做题时可能会遗忘这种方法

📕 例题引入

给定一个有序数组,找到其中指定的数,返回其下标

#include<stdio.h>
void erfen(int a[],int b,int sz)
{
int left=0;
int right=sz-1;
while(left<right)
{
int mid=(left+right)/2;
if(b>a[mid])
left=mid+1;
if(b<a[mid])
right=mid-1;
else
{printf(“找到了下标为%d\n”,mid);
break;}

}
if(left>right){
printf(“找不到”);
}
int main()
{
int b=0;
printf(“请输入1~10间的一个数\n”);
scanf("%d",&b);
int a[]={1,2,3,4,5,6,7,8,9,10};
int sz=sizeof(a)/sizeof(a[0]);
void erfen(a,b,sz);
return 0;
}

?定义两个变量记录每次分的左右端,让其中间值与数进行比较,直到出现指定数或无法再分,时间复杂度为

大家都懂,就不过多赘述了。

📰 练习巩固

1.

给定一个有序数组,如1,1,1,2,2,2,3,3,3,4,4,4,5,5,5

给定一个num,输出大于等于num最左侧的值或者小于等于num最右侧的值的下标。

假如num=3,大于等于最左侧的下标为6,小于等于最右侧的下标为8,可以二分直到二分结束

没找到例题,就用这个吧(这题我们就用最左侧吧)

?

?用一个变量记录打勾的下标(即等于num的坐标,比较最小值进行替换)

?这便是此题的解题思路,当然你也可以暴力求解复杂度O(N),二分法则是O(logN)。

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
	int num;
	int arr[] = { 1,1,1,2,2,2,3,3,3,4,4,4,5,5,5 };
	scanf("%d", &num);
	int left = 0,count=14,mid=0;
	int sz = sizeof(arr);
	int right = sz - 1;
	while (left <= right)
	{
	     mid = (left + right) / 2;
		if (num < arr[mid])
		{
			right = mid - 1;
		}
		if (num > arr[mid])
		{
			left = mid + 1;
		}
		if (num == arr[mid])
		{
			right= mid - 1;
			if (count > mid)
				count = mid;
		}
	}
	printf("%d", count);
}

?2.局部最小

给定无序数组arr,且其中相邻两个数一定不相等,例如0位置上的数小于1位置上的数,那么0位置局部最小,如果n-1位置上的数比n-2位置上的数小,那么n-1就是局部最小,如果i<i-1且i<i+1,那么,i是局部最小。

思路如下:

?

?同样,也是一直二分直到结束

162. 寻找峰值

峰值元素是指其值严格大于左右相邻值的元素。

给你一个整数数组?nums,找到峰值元素并返回其索引。数组可能包含多个峰值,在这种情况下,返回?任何一个峰值?所在位置即可。

你可以假设?nums[-1] = nums[n] = -∞?。

你必须实现时间复杂度为?O(log n)?的算法来解决此问题。

示例 1:

输入:nums = [1,2,3,1]
输出:2
解释:3 是峰值元素,你的函数应该返回其索引 2。

示例?2:

输入:nums = [1,2,1,3,5,6,4]
输出:1 或 5 
解释:你的函数可以返回索引 1,其峰值元素为 2;
?    或者返回索引 5, 其峰值元素为 6。

int findPeakElement(int* nums, int numsSize){
int left=0,right=numsSize-1;
    while(left < right)
    {
        int mid = (left + right) / 2;
        if(nums[mid] > nums[mid + 1]) 
        right = mid;  
        else 
        left = mid+1;    
    }
    return right;
}

?📰 总结:

二分法可用于:

1.有序数组找下标

2.有序数组中大于等于一个值最左侧,小于等于这个值的最右侧下标

3.局部最小,局部最大

?

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-04-22 19:01:27  更:2022-04-22 19:02:02 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 7:38:05-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码