由一个“双指针题目”引起的对平台的思考(“三数之和“)
先说题目吧,今天做了道“三数之和”
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。
示例1:
输入:nums = [-1,0,1,2,-1,-4] 输出:[[-1,-1,2],[-1,0,1]]
我“定眼”一看!豁,好熟悉,dfs,然后一顿做,我的
思路是这样的:
- 确定好dfs参数
- 发现输出是有规律的,不能盲目搜索。-----加个排序
- 发现还要判重------转String 利用SET 。基操。
- 发现返回没参数了,歪日,list的深浅拷贝很细节。
结果 318个卡在了第315个上超时。
。。。
看来不只是简单的深搜啊
加”剪枝“。
经过一系列的压榨···还是超时。
不得不向题解低头,然后发现——>竟然又是双端指针。
我在”力扣“上遇到好多思路都是双指针,在洛谷刷题这么长时间以来,由于题目是洛谷上的,搜的题解,包括百度的思路,都是“洛谷化”。明显能感觉出两个平台的风格不同,解题思路不同,我一直以来以为算法思想万变不离其宗,其实由于设置的题型,出题团队的思考习惯,都能使得解题方法另辟蹊径。
所以以后多接触不同平台,然后多看其他的题解,扩展思路。
总结:
- 双指针的优势可以在dfs的时候感觉到,因为剪枝只是做到单方向的剪枝。
- 双指针更加简洁灵活。
- 我的set处理判重并不漂亮。
- 这里的while加指针很像快排。
- 总结模板的话就是:当感觉线性,递增的问题时,或者能不能讲递归转化的时候,考虑一下双指针。
- 还得多练找感觉。
我的深搜题解(315/318 超时)
import javafx.scene.effect.SepiaTone;
import java.util.*;
/**
* @Auther Lizz
* @Date 2021/10/8
*/
public class P15 {
public static void main(String[] args) {
Solution solutio = new Solution();
int [] num = {-1,0,1,2,-1,-4};
List<List<Integer>> list = solutio.threeSum(num);
for (int i = 0; i <list.size() ; i++) {
for (int j = 0; j < list.get(i).size() ; j++) {
System.out.print(list.get(i).get(j));
}
System.out.print(" ");
}
}
static class Solution {
List<List<Integer>> ANS = new ArrayList();
int vis[];
int NUMS[];
Set set = new HashSet();
public List<List<Integer>> threeSum(int[] nums) {
vis = new int[nums.length];
NUMS = nums;//深浅拷贝
Arrays.sort(NUMS);
List list = new ArrayList();
dfs(0,0,list);//第几个数了,目前大小
return ANS;
}
private void dfs(int i, int sum,List list) {
if(sum>0 ||list.size()>3 || (list.size() == 3 && sum !=0)){
return;
}
if(list.size()==3 && sum == 0 ){
List<Integer> list1 = new ArrayList<>(3);
String s = "";
for (int j = 0; j < 3; j++) {
list1.add((Integer) list.get(j));
s+=list.get(j);
}
if( !set.contains(s)){
set.add(s);
ANS.add(list1);
}
return;
}
for (int j = i; j <NUMS.length ; j++) {
// if((list.size()==2&&sum<0&&NUMS[j]<0)||(list.size()==2&&sum>0&&NUMS[j]>0)){
// continue;
// } int j = NUMS.length-1; j >=i &&sum<=0; j--
//这里是我为剪枝做出的尝试
list.add(NUMS[j]);
dfs(j+1,sum+NUMS[j],list);
list.remove((Object) NUMS[j]);
}
}
}
}
题解双指针:
import java.util.*;
/**
* @Auther Lizz
* @Date 2021/10/8
*/
public class P15_2 {
public static void main(String[] args) {
Solution solutio = new Solution();
int [] num = {-1,0,1,2,-1,-4};
List<List<Integer>> list = solutio.threeSum(num);
for (int i = 0; i <list.size() ; i++) {
for (int j = 0; j < list.get(i).size() ; j++) {
System.out.print(list.get(i).get(j));
}
System.out.print(" ");
}
}
static class Solution {
List<List<Integer>> ANS = new ArrayList();
int NUMS[];
public List<List<Integer>> threeSum(int[] nums) {
NUMS = nums;//深浅拷贝
Arrays.sort(NUMS);
int len = NUMS.length;
for (int i = 0; i < len ; i++) {
if(NUMS[i]>0){
return ANS;
}
//去重
if(i>0 && NUMS[i]==NUMS[i-1]){
continue;
}
int curr = NUMS[i];
int l = i+1;
int r = len-1;
while (l<r){
if(curr+NUMS[l]+NUMS[r]==0){
List list = new ArrayList();
list.add(NUMS[i]);
list.add(NUMS[l]);
list.add(NUMS[r]);
ANS.add(list);
while (l<r &&NUMS[l+1]==NUMS[l])l++;
while (l<r &&NUMS[r-1]==NUMS[r])r--;
l++;
r--;
}else if(curr+NUMS[l]+NUMS[r]>0){
r--;
}else {
l++;
}
}
}
return ANS;
}
}
}