10. <tag-数组和双指针(左右指针)>-lt.344-反转字符串 + lt.16-最接近的三数之和 + lt.349-两个数组的交集 2
lt.344-反转字符串
[案例需求]
[思路分析]
- 原地逆转
[代码实现]
class Solution {
public void reverseString(char[] s) {
//左右指针法
int L = 0;
int R = s.length - 1;
char temp = ' ';
while(L < R){
temp = s[L];
s[L] = s[R];
s[R] = temp;
++L;
--R;
}
}
}
lt. 16-最接近的三数之和
[案例需求]
[思路分析]
- 前面我们说过, 双指针一般用于有序的数组, 这道题的数组虽然是无序的, 但是由于题目中并没有对时间复杂度做出限定. 我们大可以先把数组排序, 然后利用左右指针遍历后两个加数.
- 题目要求是与target值差距最小的三数之和, 那我们只需设置一个minSum存储与target差距较小的三数之和, 通过跟每次循环中的三数之和比较, 来达到不断更新较小值直到最优的目的;
- 具体思路如下:
- 利用数组遍历第一个加数, 每一次遍历就是固定一个加数, 使用左右指针寻找后两个加数的过程;
- nums[i] + nums[L] + nums[R] == target, 我们直接返回就好;
- nums[i] + nums[L] + nums[R] < target. 由于已经排序, 直接移动L指针;
- nums[i] + nums[L] + nums[R] > target. 由于已经排序, 直接移动R指针;
- 上面第3或第4步执行之后. 就立刻比较当前的三数之和和target的差值的绝对值, 更新较小值;
[代码实现]
class Solution {
public int threeSumClosest(int[] nums, int target) {
//遍历第一个数, 后两个加数用指针,
//三数之和不断更新, 何时: 与target的差值绝对值最小;
// 绝对值方法 Math.abs();
int left,right = 0;
int threeSum = 0;
int minSum = nums[0] + nums[1] + nums[2];
Arrays.sort(nums);
for(int i = 0; i < nums.length; i++){
left = i + 1;
right = nums.length - 1;
while(left < right){
threeSum = nums[i] + nums[left] + nums[right];
if(threeSum > target){
--right;
}else if(threeSum < target){
++left;
}else{
return threeSum;
}
//比较每次遍历时, 三数之和与target差值的绝对值大小, 更新较小的值
if(Math.abs(threeSum - target) < Math.abs(minSum - target))
minSum = threeSum;
}
}
return minSum;
}
}
lt.349-两个数组的交集
[案例需求]
[思路分析]
- 常规思路就是对两个数组分别排序后, 设置两个指针分别指向两个数组的0号索引处, 循环结束条件就是指针到达其中任一数组的末尾;
- 又因为要求我们输出结果中每个元素是唯一的, 所以, 我们可以把两数组的交集存储在Set集合中.
- 最后把Set集合转为int[]. 注意这里转换的方法:
set集合.stream().mapToInt(Integer::valueOf).toArray();
- 思路很简单, 效率也很低;
[代码实现]
public int[] intersection(int[] nums1, int[] nums2) {
//设置set存放交集, 结果把set转为int[]并返回
Arrays.sort(nums1);
Arrays.sort(nums2);
Set<Integer> resSet = new HashSet<Integer>();
int left = 0;
int right = 0;
while(left < nums1.length && right < nums2.length){
if(nums1[left] < nums2[right]){
left++;
}else if(nums1[left] > nums2[right]){
right++;
}else{
resSet.add(nums1[left]);
left++;
right++;
}
}
return resSet.stream().mapToInt(Integer::valueOf).toArray();
}
优化版本:
- 我们把对两个数组的排序砍掉, 把前一个数组nums1, 遍历存储到Set1中,
- 而对于nums2, 我们对nums2进行遍历, 通过
set.contains(obj)
判断nums2中的数是否跟set集合中的一致; - 如果一致的话, 说明是重叠元素, 在这里我们还是新建一个Set2来存储重叠元素(为什么还是用集合存, 因为重叠元素不定长度)
- 新建结果数组res, 遍历Set2, 依次赋值给数组中的对应索引, 返回结果数组即可;
class Solution {
public int[] intersection(int[] nums1, int[] nums2) {
if(nums1.length == 0 || nums2.length == 0) return new int[]{};
Set<Integer> set1 = new HashSet<>();
Set<Integer> set2 = new HashSet<>();
for(int i : nums1){
set1.add(i);
}
for(int i : nums2){
if(set1.contains(i)){
set2.add(i);
}
}
int[] res = new int[set2.size()];
int j = 0;
for(int i : set2){
res[j++] = i;
}
//通过遍历集合, 把数值赋值给数组, 要比上面的 xx.stream().mapToInt(Integer::valueOf).toArray() 快得多
return res;
}
}
比上面排序+双指针要快了 3~4ms.
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)