利用双指针技巧解决数组和字符串中的一些问题【Java】【leetcode】【双指针技巧】
双指针技巧 一
双指针技巧 —— 情景一
问题:反转数组中的元素。
分析:其思想是将第一个元素与末尾进行交换,再向前移动到下一个元素,并不断地交换,直到它到达中间位置。我们可以同时使用两个指针来完成迭代:一个从第一个元素开始,另一个从最后一个元素开始。持续交换它们所指向的元素,直到这两个指针相遇。
总结:总之,使用双指针技巧的典型场景之一是你想要从两端向中间迭代数组。
这时你可以使用双指针技巧:一个指针从始端开始,而另一个指针从末端开始。
值得注意的是,这种技巧经常在排序数组中使用。
反转字符串(344. Reverse String)
编写一个函数,其作用是将输入的字符串反转过来。
输入字符串以字符数组 char[] 的形式给出。
不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的
额外空间解决这一问题。
你可以假设数组中的所有字符都是 ASCII 码表中的可打印字符。
示例 1:
输入:[“h”,“e”,“l”,“l”,“o”]
输出:[“o”,“l”,“l”,“e”,“h”]
示例 2:
输入:[“H”,“a”,“n”,“n”,“a”,“h”]
输出:[“h”,“a”,“n”,“n”,“a”,“H”]
class Solution { public void reverseString(char[] s) { int head = 0; int tail = s.length - 1; char temp; while (head < tail) { temp = s[head]; s[head] = s[tail]; s[tail] = temp; head++; tail--; } System.out.println(Arrays.toString(s)); } }
数组拆分 I (561. Array Partition I)
给定长度为 2n 的数组, 你的任务是将这些数分成 n 对, 例如:
(a1, b1), (a2, b2), …, (an, bn) ,使得从1 到 n 的 min(ai, bi) 总和最大。
示例 1:
输入: [1,4,3,2]
输出: 4
解释: n 等于 2, 最大总和为 4 = min(1, 2) + min(3, 4).
提示:
n 是正整数,范围在 [1, 10000].
数组中的元素范围在 [-10000, 10000].
//分析:排序原数组然后对数组的奇数为求和并返回该值即可 //此处的排序方法选择了直接调用而非自己重写排序 class Solution { public int arrayPairSum(int[] nums) { Arrays.sort(nums); int sum = 0; for (int i = 0; i < nums.length; i += 2) { sum += nums[i]; } return sum; } }
两数之和 II - 输入有序数组(167. Two Sum II - Input array is sorted)
给定一个已按照升序排列 的有序数组,找到两个数使得它们相加之和等于目标数。
函数应该返回这两个下标值 index1 和 index2,其中 index1 必须小于 index2。
说明:
返回的下标值(index1 和 index2)不是从零开始的。
你可以假设每个输入只对应唯一的答案,而且你不可以重复使用相同的元素。
示例:
输入: numbers = [2, 7, 11, 15], target = 9
输出: [1,2]
解释: 2 与 7 之和等于目标数 9 。因此 index1 = 1, index2 = 2 。
class Solution { public int[] twoSum(int[] numbers, int target) { int head = 0; int tail = numbers.length - 1; while (true) { int sum = numbers[head] + numbers[tail]; if (sum == target) { return new int[]{head + 1, tail + 1}; } if (sum > target) { tail--; } else { head++; } } } }
双指针技巧 二
双指针技巧 —— 情景二
有时,我们可以使用两个不同步的指针来解决问题
示例:给定一个数组和一个值,原地删除该值的所有实例并返回新的长度。
**分析:**如果我们没有空间复杂度上的限制,那就更容易了。我们可以初始化一个新的数组来存储答案。如果元素不等于给定的目标值,则迭代原始数组并将元素添加到新的数组中。
实际上,它相当于使用了两个指针,一个用于原始数组的迭代,另一个总是指向新数组的最后一个位置。
重新考虑空间限制
现在让我们重新考虑空间受到限制的情况。
我们可以采用类似的策略,我们继续使用两个指针:一个仍然用于迭代,而第二个指针总是指向下一次添加的位置。
总结:
这是你需要使用双指针技巧的一种非常常见的情况:
同时有一个慢指针和一个快指针。
解决这类问题的关键是
确定两个指针的移动策略。
与前一个场景类似,你有时可能需要在使用双指针技巧之前对数组进行排序,也可能需要运用贪心想法来决定你的运动策略。
移除元素 (27. Remove Element)
给定一个数组 nums 和一个值 val,你需要原地移除所有数值等于 val 的元素,返回移除后数组的新长度。
不要使用额外的数组空间,你必须在原地修改输入数组< 22159 /strong>并在使用 O(1) 额外空间的条件下完成。
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
示例 1:
给定 nums = [3,2,2,3], val = 3,
函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。
你不需要考虑数组中超出新长度后面的元素。
示例 2:
给定 nums = [0,1,2,2,3,0,4,2], val = 2,
函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。
注意这五个元素可为任意顺序。
你不需要考虑数组中超出新长度后面的元素。
说明:
为什么返回数值是整数,但输出的答案是数组呢?
请注意,输入数组是以“引用”方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。
你可以想象内部操作如下:
// nums 是以**“引用”方式传递的。也就是说,不对实参作任何拷贝
int len = removeElement(nums, val);
// 在函数里修改输入数组对于调用者是可见的。
// 根据你的函数返回的长度, 它会打印出数组中该长度范围内**的所有元素。
for (int i = 0; i < len; i++) {
print(nums[i]);
}
class Solution { public int removeElement(int[] nums, int val) { if (nums.length == 0) { return 0; } int fast; int slow = 0; for (fast = 0; fast < nums.length; fast++) { if (nums[fast] != val) { nums[slow] = nums[fast]; slow++; } } return slow; } }
最大连续1的个数 (485. Max Consecutive Ones)
给定一个二进制数组, 计算其中最大连续1的个数。
示例 1:
输入: [1,1,0,1,1,1]
输出: 3
解释: 开头的两位和最后的三位都是连续1,所以最大连续1的个数是 3.
注意:
输入的数组只包含 0 和1。
输入数组的长度是正整数,且不超过 10,000。
class Solution { public int findMaxConsecutiveOnes(int[] nums) { // 新建一个数组记录连续一的个数,使用双指针技巧 int[] record = new int[nums.length]; int slow = 0; for (int i = 0; i < nums.length; i++) { if (nums[i] == 1) { record[slow] = 1; slow++; } else { slow = 0; } } //设置计数 int count = 0; //便利原数组,遇到0停止,返回第一个0前的1的个数 for (int i = 0; i < record.length; i++) { if (record[i] != 1) { break; } else { count++; } } return count; } }
长度最小的子数组 (209. Minimum Size Subarray Sum)
给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的连续子数组。如果不存在符合条件的连续子数组,返回 0。
示例:
输入: s = 7, nums = [2,3,1,2,4,3]
输出: 2
解释: 子数组 [4,3] 是该条件下的长度最小的连续子数组。
进阶:
如果你已经完成了O(n) 时间复杂度的解法, 请尝试 O(n log n) 时间复杂度的解法。
class Solution { public int minSubArrayLen(int s, int[] nums) { if (nums.length == 0) { return 0; } if (nums[0] >= s) { return 1; } // 当输入数组的长度大于等于二时,试着使用快慢指针计算最小的连续数组的长度 int fast = 1; int slow = 0; int max = nums.length - 1; int res = max + 2; int sum = nums[fast] + nums[slow]; while (fast < max) { // int sum = nums[fast] + nums[slow]; while (fast < max && sum < s) { fast++; sum += nums[fast]; } while (sum >= s) { sum -= nums[slow]; slow++; } res = res > (fast - slow + 2) ? (fast - slow + 2) : res; } return res == max + 2 ? 0 : res; } }
- 存储中的一些技巧(利用数组下标解决问题总结)
- 高级Java研发师在解决大数据问题上的一些技巧
- 关于数组指针,指针数组和字符串数组的一些问题
- 算法学习笔记之四:巧妙运用指针解决链表、字符串、数组等问题(同向双指针VS对向双指针)
- java语言中解决一些安全问题的技巧(安全编程非常重要标签)
- 解决java中文问题的一些资源
- 关于字符串与字符数组的一些小问题
- java中关于基本类型和数组的一些注意问题
- java如何用数组解决大数阶乘的问题,例如求n!,n=100000
- 第十七周 利用指针和数组的方法分别查询字符串的个数
- JAVA 写中文字符串到指定文件 中文乱码 问题解决
- 使用asx3m与xstream配合解决flex与java利用httpservice传递xml数据问题
- C++利用指针数组和快排对输入的字符串进行排序
- Java的中英文混合截取字符串的问题解决方法
- 【C#学习】利用数组解决约瑟夫环问题
- java利用poi 读写(导入导出)word、excel(数组越界求解决办法)
- Java中字符串中存在空格引发的问题,及解决方法。
- 关于将Java中序列化对象写入byte[]遇到的一些问题及解决方法
- java字符串星号、问号匹配问题解决方法
- 使用asx3m与xstream配合解决flex与java利用httpservice传递xml数据问题