一 LC283.移动零
题目要求:
给定一个数组
nums
,编写一个函数将所有0
移动到数组的末尾,同时保持非零元素的相对顺序。请注意 ,必须在不复制数组的情况下原地对数组进行操作。
思路分析:
本题是很经典的一道快慢指针题目。我们可以定义两个指针,起始都指向数组的首个元素。其中,我们让快指针循环遍历整个数组,当快指针移动到数组末尾时,退出循环。
在遍历过程中,我们始终让快指针向前移动1,如果此时快指针指向的元素为0,则继续向前移动,如果不为0,则与慢指针指向的元素进行交换,然后两个指针同时向前移动。当快指针遍历完毕整个数组,则交换全部完成。
完整代码示例:
class Solution {
public void moveZeroes(int[] nums) {
int f = 0; // 左指针指向首个元素
int s = 0; // 慢指针
while(f != nums.length) {
if(nums[f] == 0) {
f++;
}else {
int temp = nums[f];
nums[f] = nums[s];
nums[s] = temp;
s++;
f++;
}
}
}
}
二 LC11.盛最多水的容器
题目要求:
给定一个长度为
n
的整数数组height
。有n
条垂线,第i
条线的两个端点是(i, 0)
和(i, height[i])
。找出其中的两条线,使得它们与
x
轴共同构成的容器可以容纳最多的水。返回容器可以储存的最大水量。
说明:你不能倾斜容器。
思路分析:
这道题目同样难度没有那么高,分析题目,不难看出,我们需要找到数组中两个元素间数值较小的那个元素 * 数组元素下标差最大的那个结果。
我们同样使用双指针的方法完成,这次我们定义两个指针,分别指向数组的头尾(此时元素下标差最大),我们计算这时两个元素中较小数 * 下标差的值,并进行记录。这时,如果我们希望扩大乘积的值,那么只能考虑增加最小元素的数值,因此,我们将指向较小数值元素的指针向中间移动,保留指向较大元素的指针不变。继续计算乘积,并将新计算出的结果与之前的结果对比,留下较大的那一个。直到两个指针相遇,距离变为0时结束循环。
完整代码示例:
class Solution {
public int maxArea(int[] height) {
int res = 0;
int l = 0;
int r = height.length - 1;
while( l <= r ) {
int area = Math.min(height[l], height[r]) * (r - l);
if(area > res) res = area;
if (height[l] <= height[r]) {
l = l + 1;
}
else {
--r;
}
}
return res;
}
}
三 LC15.三数之和
题目要求:
给你一个整数数组
nums
,判断是否存在三元组[nums[i], nums[j], nums[k]]
满足i != j
、i != k
且j != k
,同时还满足nums[i] + nums[j] + nums[k] == 0
。请你返回所有和为0
且不重复的三元组。注意:答案中不可以包含重复的三元组。
思路分析:
本题要求找到满足条件的所有三元组,并去除重复的可能。因此我们考虑使用双指针来进行。首先我们对数组进行排序,遍历排序后的数组。定义两个指针,分别指向当前遍历元素的下一个元素和数组末尾元素,当左指针小于右指针时,进行循环。此外还需要判断如果当前元素已经大于0了,那么其后面的元素一定大于0,不满足题目要求,可以直接return。当遍历到重复元素时也直接跳过,避免出现重复的解。
当当前元素与左右指针指向的元素之和等于0时,记录该结果,并移动指针(注意跳过重复元素);如果当前元素与左右指针指向的元素之和大于0,则将右指针向左移动,否则向右移动左指针。
完整代码示例:
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> lists = new ArrayList<>();
Arrays.sort(nums);
int len = nums.length;
for(int i = 0;i < len;++i) {
if(nums[i] > 0) return lists; // nums[i]已经大于0了,直接return
if(i > 0 && nums[i] == nums[i-1]) continue; //遍历到重复元素时直接跳过,避免出现重复解。
int curr = nums[i];
int L = i+1, R = len-1;
while (L < R) {
int tmp = curr + nums[L] + nums[R];
if(tmp == 0) {
List<Integer> list = new ArrayList<>(); // 记录结果
list.add(curr);
list.add(nums[L]);
list.add(nums[R]);
lists.add(list);
while(L < R && nums[L+1] == nums[L]) ++L; // 跳过重复元素
while (L < R && nums[R-1] == nums[R]) --R; // 跳过重复元素
++L;
--R;
} else if(tmp < 0) {
++L;
} else {
--R;
}
}
}
return lists;
}