双指针算法

力扣:704、344【反转字符串】、167、5【回文串 暴力解法】、

无重复+有序数组问题 首先考虑双指针解法

1.结果比目标,小了要变大,左指针右移+,

2.结果比目标,大了要变小,右指针左移-,

3.中心开花🌼相背走,左指针减减右指针加(加)。

原地修改输入数组:不增加与原数组长度相关的空间。

双指针交换 最中间独立的不用管

a b c d e

e b c d a

模板:

int left = 0;int right = s.length - 1;
// 可能取等 也可能不取等号
while(left <= right){
    //结果比目标,小了要变大,左指针右移+
    
    //结果比目标,大了要变小,右指针左移-
}

回文数:正着读反着读都是一样的

5【回文串】

暴力解法:

// 暴力解法 找出所有的子串
    public String power(String s){
        int max = 0;
        String maxStr = "";
        for(int i=0 ; i<s.length() ;i++){
            for(int j=i+1;j<=s.length();j++){
                String str = s.substring(i,j);
                if(isPalindromic(str) && max < str.length()){
                    max = str.length();
                    maxStr = str;
                }
            }
        }
        return maxStr;
    }
    public Boolean isPalindromic(String s){
        int left = 0;
        int right = s.length() - 1;
        while(left < right){
            if(s.charAt(left) == s.charAt(right)){
                left++;
                right--;
            }else{
                return false;
            }
        }
        return true;
    }

如果长度为奇数,认为有1个中心字符。如果长度为偶数,认为有2个中心字符。

如果输入相同的left和right,相当于找长度为奇数的回文串

如果输入相邻的left和right,相当于找长度为偶数的回文串

直接计算解法:【略慢了】

这里没必要做计算,返回的就是以当前为中心找到最长的字符串了。

public String find(String s,int left,int right){
        int max = 0;
        String maxStr="";
        while(left>=0 && right<=s.length()-1 && s.charAt(left) == s.charAt(right)){
            String temp = s.substring(left,right+1);
            left--;
            right++;  
            if(max < temp.length()){
                max = temp.length();
                maxStr = temp;
            }  
        }
        return maxStr;
    }

【更快解法】

public String find(String s,int left,int right){
        while(left>=0 && right<=s.length()-1 && s.charAt(left) == s.charAt(right)){
            left--;
            right++;  
        }
        return s.substring(++left,right);
}

力扣125【验证回文串】

如果在将所有大写字符转换为小写字符、并移除所有非字母数字字符之后,短语正着读和反着读都一样。则可以认为该短语是一个 回文串

字母和数字都属于字母数字字符。

给你一个字符串 s,如果它是 回文串 ,返回 true ;否则,返回 false

解答:

注意将字符串转为小写字符,然后Character里有个isDigOrNum()方法判断一下是否是数字和字母。

392. 判断子序列

给定字符串 st ,判断 s 是否为 t 的子序列。

字符串的一个子序列是原始字符串删除一些(也可以不删除)字符而不改变剩余字符相对位置形成的新字符串。(例如,"ace"是"abcde"的一个子序列,而"aec"不是)。

进阶:

如果有大量输入的 S,称作 S1, S2, ... , Sk 其中 k >= 10亿,你需要依次检查它们是否为 T 的子序列。在这种情况下,你会怎样改变代码?

优秀代码:

public boolean isSubsequence(String s, String t) {
        int i = 0, j = 0;
        
        int n = s.length();
        
        int m = t.length();
        
        while (i < n && j < m){
            if (s.charAt(i) == t.charAt(j)){
                i++;
            }
            j++;
        }
        return i == n;
    }

解答:

t的指针会一直移动,s只有匹配上了才会移动。只要任意指针出界就停止指针移动,然后判断s是否都匹配完全了。

11. 盛最多水的容器

给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。

找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。

返回容器可以储存的最大水量。

说明:你不能倾斜容器。


示例 1:

输入:[1,8,6,2,5,4,8,3,7]
输出:49 
解释:图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。

示例 2:

输入:height = [1,1]
输出:1

解答:

因此,初始化双指针分列水槽左右两端,循环每轮将短板向内移动一格,并更新面积最大值,直到两指针相遇时跳出;即可获得最大面积。
 

疑惑点:

8 7 6 8,假如我是这4个数字

那此时移动右指针最后得到的结果是 8 7 6 得到面积:12,

移动左指针得到的结果是7 6 8 得到面积:14

都会比 8 7 6 8要小 面积:24。

因为两个一样高 再往里面找也最多只能找到高度一样或者更小的板子【因为要取决于短板多高 你再高就算100也无济于事】然后宽度还变小 所以你往里头走目的是找比自己更高的两条板子 比如 8 100 105 8

15. 三数之和

给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != j、i != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请

你返回所有和为 0 且不重复的三元组。

注意:答案中不可以包含重复的三元组。

示例 1:

输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
解释:
nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0 。
nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0 。
nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0 。
不同的三元组是 [-1,0,1] 和 [-1,-1,2] 。
注意,输出的顺序和三元组的顺序并不重要。

示例 2:

输入:nums = [0,1,1]
输出:[]
解释:唯一可能的三元组和不为 0 。

示例 3:

输入:nums = [0,0,0]
输出:[[0,0,0]]
解释:唯一可能的三元组和为 0 。

优秀代码:

public List<List<Integer>> threeSum(int[] nums) {
        List<List<Integer>> arr = new ArrayList<>();
        if(nums.length < 3){
            return arr;
        }
        Arrays.sort(nums);
        for (int i = 0; i < nums.length; i++) {
            if(nums[i] > 0){
                break;
            }
            // 第一个不去重 第二次出现才去重
            if(i > 0 && nums[i] == nums[i-1]){
                continue;
            }
            int left = i + 1;
            int right = nums.length - 1;
            while (left < right){
                int sum = nums[i] + nums[left] + nums[right];
                if(sum == 0){
                    arr.add(Arrays.asList(nums[i],nums[left],nums[right]));
                    while (left < right && nums[left] == nums[left+1]){
                        left++;
                    }
                    while (left < right && nums[right] == nums[right-1]){
                        right--;
                    }
                    // 非常重要 去重以后还要记得再执行一次!!!!!!!
                    left++;
                    right--;
                } else if (sum < 0) {
                    left++;
                }
                else if (sum > 0) {
                    right--;
                }
            }
        }
        return arr;
    }

为什么三数之和的else if(sum > 0){ right--; }else { left++; }这个代码不能换成else if(sum > 0){ left++; }else { right--; }呢

  • 如果sum > 0且我们执行left++,这将会使得总和更大,因为我们向右移动了左指针,这与我们试图减小总和以达到0的目标相违背。
  • 如果sum < 0且我们执行right--,这将会使得总和更小,因为我们向左移动了右指针,这又与我们试图增加总和以达到0的目标相违背。
  • 并且指针不能倒退,所以只有一种走法


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值