算法基础__two pointers
Easy 级例题:给定一个递增的具有n个元素的正整数序列arr和一个正整数s,求序列中两个不同位置的数a和b,使他们的和恰好等于s,输出所有满足条件的结果i和j。如序列arr = {1, 2, 3, 4, 5, 6}和正整数s = 9, 就有 4 + 5 和 3 + 6 。
本例最简单的方法就是利用二重循环枚举所有的可能性,得出结果。但是这样做的时间复杂度为O(n^2),显然是低效率的。
这里利用序列本身的特性和双指针two pointers的思想来解决这个问题。
- 对于一个确定的arr[i], 如果某个的arr[j]满足
arr[i] + arr[j] == s
时,有arr[i] + arr[j + 1] > s
,则不需要对 j 以后的情况进行枚举。 - 对于某个arr[i], 可以找到一个确定的arr[j]当
arr[i] + arr[j] == s
时,有arr[i+1] + arr[j] > s
,则不需要对 i 以后的情况进行枚举。
那么对于这个问题可以采用two pointers的思想。先让i = 0, j = n - 1,也就是i指针指向第一个元素,j指针指向最后一个元素。根据arr[i] + arr[j]和s的大小来决定i向右移还是j向左移,直到i >= j。
判断条件如下:
1)如果arr[i] + arr[j] == s
,则输出结果。且由于序列递增,可以知道arr[i+1] + arr[j] > s
,arr[i] + arr[j-1] < s
,arr[i+1] + arr[j-1]
和s的大小关系不确定,所以等于s的结果只能是在[i+1, j-1]之间。
2)如果arr[i] + arr[j] < s
,则有arr[i] + arr[j-1] < s
,但是arr[i+1] + arr[j]
和s的大小关系不确定,则i向右移,i++。
3)如果arr[i] + arr[j] > s
,则有arr[i+1] + arr[j] > s
,但是arr[i] + arr[j-1]
和s的大小关系不确定,则j向左移,j–。
代码如下:
while(i < j)
{
if(arr[i] + arr[j] == s)
{
cout<<"result = " << i << "+" << j <<endl;
}
else if(arr[i] + arr[j] < s)
{
i++;
}
else
{
j--;
}
}
Easy+ 级例题:序列合并问题,将两个递增序列arr_1和arr_2合并为一个递增序列arr_3;
将i设置为arr_1序列的首元素,j设置为arr_2序列的首元素,然后通过比较大小来看那个该放入序列arr_3。
1)如果arr_1[i] > arr_2[j]
,说明现在arr_2[j]
是当前最小的一个,放入arr_3中,然后j++。
2)如果arr_1[i] < arr_2[j]
,说明现在arr_1[i]
是当前最小的一个,放入arr_3中,然后i++。
1)如果arr_1[i] == arr_2[j]
,则任选一个放入arr_3,然后把对应的pointer++。
//l1为数组arr_1的元素个数,l2为数组arr_2的元素个数
int mergeArray(const int arr_1[], const int arr_2[], int arr_3[], int l1, int l2)
{
int i = 0, j = 0, index = 0;
while(i < l1 && j < l2)
{
if(arr_1[i] >= arr_2[j]) {
arr_3[index++] = arr_2[j++];
}
else {
arr_3[index++] = arr_1[i++];
}
}
//将剩余的全部加入到数组arr_3中
while(i < l1) arr_3[index++] = arr_1[i++];
while(j < l2) arr_3[index++] = arr_2[j++];
return index;//返回arr_3数组元素个数
}