力扣: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. 判断子序列
给定字符串 s 和 t ,判断 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的目标相违背。
- 并且指针不能倒退,所以只有一种走法