春招Leetcode刷题日记-D3-双指针算法-归并两个有序数组&&Two Sum


什么是双指针算法

1、双指针主要用于遍历数组,两个指针指向不同的元素,从而协同完成任务。也可以延伸到多
个数组的多个指针。
2、若两个指针指向同一数组,遍历方向相同且不会相交,则也称为滑动窗口(两个指针包围的区域即为当前的窗口),经常用于区间搜索。
3、若两个指针指向同一数组,但是遍历方向相反,则可以用来进行搜索,待搜索的数组往往是排好序的。
4、常见的c++指针操作方式:

int x;
int * p1 = &x; // 指针可以被修改,值也可以被修改
const int * p2 = &x; // 指针可以被修改,值不可以被修改(const int)
int * const p3 = &x; // 指针不可以被修改(* const),值可以被修改
const int * const p4 = &x; // 指针不可以被修改,值也不可以被修改
// addition是指针函数,一个返回类型是指针的函数
int* addition(int a, int b) {
	int* sum = new int(a + b);
	return sum;
}
int subtraction(int a, int b) {
	return a - b;
}
int operation(int x, int y, int (*func)(int, int)) {
	return (*func)(x,y);
}
// minus是函数指针,指向函数的指针
int (*minus)(int, int) = subtraction;
int* m = addition(1, 2);
int n = operation(3, *m, minus);

力扣88. 合并两个有序数组

题目链接:88. 合并两个有序数组

在这里插入图片描述
在这里插入图片描述

思路

1、这种题是最基本的套路提,最简单的想法就是:两个指针在两个数组头部进行遍历,每次从两个指针指向的位置处选择小的元素,最后在把没放进去的放进去即可。
2、但需要额外存于一个新数组,空间复杂度不好。
3、所以,采取优化手段,我们两个指针,从两个数组尾部开始遍历,每次选大的加入nums尾部(已经提前开好空间了),这样就可以省下空间

代码

class Solution {
public:
	void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
		int i = m - 1, j = n - 1, k = m + n - 1;//分别指向nums1,nums2,k用于在nums1尾部写入新数据
		while (i >= 0 && j >= 0) {
			if (nums2[j] > nums1[i]) {//每次放入大的元素进入nums1尾部
				nums1[k] = nums2[j];
				j--;
			}
			else {
				nums1[k] = nums1[i];
				i--;
			}
			k--;
		}
		while (i >= 0) {//把剩余的放进去
			nums1[k] = nums1[i];
			i--;
			k--;
		}
		while (j >= 0) {
			nums1[k] = nums2[j];
			j--;
			k--;
		}
	}
};

力扣167. 两数之和 II - 输入有序数组

题目链接:167. 两数之和 II - 输入有序数组
在这里插入图片描述
在这里插入图片描述

思路

拿来这个题,最基本的想法就是,我遍历一遍数组,访问到i处时,再遍历一遍数组,查找target-numbers[i]是否在数组中,这是O(n^2)的想法,也是最朴素的想法。

思路一:时间复杂度O(nlogn)算法

1、但是,只要是涉及在有序数组中查找一个数值的问题的时候,一定一定一定不要犹豫!直接选择二分查找!
2、注意读题,答案中下标顺序,一定是递增的,所以从左到右枚举第一个i,再对第二个数二分查找就行,返回下标
3、注意,第二个数的下标,一定不能和第一个数的下标重合,二分查找的时候注意判断。
4、根据题意,最后下标都加一

代码

class Solution {
public:
	vector<int> twoSum(vector<int>& numbers, int target) {//二分查找
		int n = numbers.size();
		for (int i = 0; i < n; i++) {
			int one = numbers[i];
			int two = target - one;
			int pos = find(numbers, 0, n - 1, two, i);
			if (pos != -1) {
				return { i + 1,pos + 1 };
			}
		}
		return {};
	}
	//二分查找参数说明:数组(传入引用,加快效率),左边界,右边界,目标数,第一个数对应的下标
	int find(vector<int>& numbers, int left, int right, int two, int i) {//二分查找
		if (left > right) {
			return -1;
		}
		int mid = (left + right) / 2;
		if (numbers[mid] == two && mid != i) {
			return mid;
		}
		else if (numbers[mid] > two) {
			return find(numbers, left, mid - 1, two, i);
		}
		return find(numbers, mid + 1, right, two, i);
	}
};

思路二:时间复杂度O(n)–双指针算法

1、我们一定要善于具体化搜索过程,根据朴素搜索定义,相当于一个指针i在一个轴上面搜索,另一个指针j在一个轴上面搜索,也就是,可以具体看做在一个二维平面上搜索,每一个(i,j)里面的值,代表着numbers[i]+numbers[j],相当于在一个二维矩阵(已经排好序)中搜索目标值。
2、但是,由于题意,我们只能在上半三角矩阵中搜索,如图中白色框框:
在这里插入图片描述
3、所以,这道题就转化为了,和240. 搜索二维矩阵 II一模一样的思路,从左下角或者右上角开始,在O(n)内即可完成搜索。下面,我将介绍这种搜索的原理
4、因为本体限制,所以只能从右上角在(0,7)处开始搜索,如果不是目标要么大于target,要么小于target

当小于target时,因为在0行中,(0,7)已经是最大了,再想要更大的数,i=0根本满足不了,直接省略0行,i++
当大于target时,因为在7列中,(0,7)已经是最小了,再想要更小的数,j=7根本满足不了,直接省略7列,j - -

5、综上,可以看到,无论 结果是大了还是小了,我们都可以排除掉一行或者一列的搜索空间。经过 n 步以后,就能排除所有的搜索空间,检查完所有的可能性。搜索空间的减小过程如下面动图所示:

请添加图片描述
这也就是,这一类已经全部排序完毕的二维空间中,快速查找的思路。

代码

class Solution {
public:
	vector<int> twoSum(vector<int>& numbers, int target) {//双指针
		int i = 0, j = numbers.size() - 1;
		while (i < j) {
			if (numbers[i] + numbers[j] < target) {
				i++;
			}
			else if (numbers[i] + numbers[j] > target) {
				j--;
			}
			else {
				return { i+1,j+1 };
			}
		}
		return {};
	}
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
2023年3月11日,美团聘笔试中共包含五道编程目。以下是对每道目的简要说明: 1. 目一:这道目要求解决一个数字统计的问。可能涉及到的知识点包括数据结构、循环和条件判断等。解决问的思路可能是使用字典等数据结构来保存统计结果,并使用循环逐个读取输入数据并进行统计。 2. 目二:这道目可能是一个字符串处理的问。需要使用字符串的方法进行操作,如提取、拼接、查找和替换等。可能的解决思路包括使用正则表达式、切片和遍历等。 3. 目三:这道目可能涉及到算法和数据结构的知识。可能是一道涉及到数组、链表、树等数据结构的问。解决思路可能包括遍历、递归、搜索和排序等。 4. 目四:这道目可能是一个动态规划的问。需要根据给定的条件和规则,通过动态规划的方式求解问。解决思路包括定义状态和转移方程,使用递推或记忆化搜索进行求解。 5. 目五:这道目可能是一个图论或网络问。需要根据给定的图或网络结构,解决一个相关的问。可能涉及到广度优先搜索、深度优先搜索、最短路径等知识。解决思路可能包括使用图或网络的相关算法进行求解。 以上只是对这五道编程目的一些可能情况进行的简要描述,具体的目内容可能会有所不同。希望这些信息能对你有所帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JLU_LYM

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值