系列博客目录
理论知识
双指针虽然是直接用它的理论知识来命名,但是使用两个指针的这一点只是它的表象。
双指针:由于数据特征的有序性(大小或者正负),所以可以证明当前节点一定是优于过往节点,从而可以通过数据的维度数量的指针,逐步的迭代收敛最终找到最优解。
本质:学过信息论的人知道,信息越随机,它的熵越小,越只能通过遍历。所以带着某种顺序信息的序列,有可能通过双指针来加快算法速度。
数据具有规则性的情况可以尝试双指针。
例题
移动零:利用指针记录已经检查过的、和已经调整过的数据位置将数据按处理未处理进行分割。
盛最多水的容器:根据实际的目标公式,选择一个具有单调性的变量,利用指针记录边界,再迭代收敛更新。
三数之和:通过分析时间复杂度极限,在不会对速度造成影响的情况下,通过优化数据形式来添加数据的规则性。
125.验证回文串
class Solution {
public boolean isPalindrome(String s) {
int left = 0;
int right = s.length() - 1;
while(left < right){
while(left <right &&!Character.isLetterOrDigit(s.charAt(left))){
left ++;
}
while(left <right &&!Character.isLetterOrDigit(s.charAt(right))){
right --;
}
if(Character.toLowerCase(s.charAt(left))!= Character.toLowerCase(s.charAt(right))){
return false;
}
left++;
right--;
}
return true;
}
}
392.判断子序列
class Solution {
public boolean isSubsequence(String s, String t) {
int n = s.length();
int m = t.length();
int i=0 ,j = 0;
while(i<n&&j<m){
if(s.charAt(i) == t.charAt(j)){
i++;
}
j++;
}
return i==n;
}
}
167.两数之和Ⅱ-输入有序数组
class Solution {
public int[] twoSum(int[] numbers, int target) {
HashMap<Integer, Integer> hashMap = new HashMap<>();
for (int i = 0; i < numbers.length; i++) {
if(hashMap.containsKey(target - numbers[i])){
return new int[]{hashMap.get(target - numbers[i])+1, i+1};
}
hashMap.put(numbers[i],i);
}
return null;
}
}
283. 移动零 简单 非面试经典150题
问题描述:
给定一个数组 nums
,编写一个函数将所有的 0 移动到数组的末尾,同时保持非零元素的相对顺序。要求原地操作,即不使用额外的数组空间。
示例:
-
输入:
nums = [0, 1, 0, 3, 12]
输出:[1, 3, 12, 0, 0]
-
输入:
nums = [0]
输出:[0]
提示:
- 1 <=
nums.length
<= 10^4 - -
2
31
2^{31}
231 <=
nums[i]
<= 2 31 2^{31} 231 - 1
进阶:
- 尽量减少操作次数。
题解
看了蜜糖之后自己写的,1ms击败100%。思路就是通过index来记录不是0的数的个数(假设这是个不断扩大的数组),并且遍历到不是0的数就往不是零的(不断扩大的)数组里面添加。这里面的指针设置非常巧妙。
class Solution {
public void moveZeroes(int[] nums) {
int index = 0;
for (int i = 0; i < nums.length; i++) {
if(nums[i]==0) continue;
else{
nums[index] = nums[i];
}
index++;
}
for (int i = index; i < nums.length; i++) {
nums[i] = 0;
}
}
}
11. 盛最多水的容器 中等
问题描述:
给定一个长度为 n
的整数数组 height
,数组中的每个元素代表一个垂直线的高度。第 i
条线的两个端点是 (i, 0)
和 (i, height[i])
。找到两条线,使得它们与 x
轴共同构成的容器可以容纳最多的水。返回容器可以储存的最大水量。
注意: 不能倾斜容器。
示例:
-
输入:
[1, 8, 6, 2, 5, 4, 8, 3, 7]
输出:49
解释: 在这个例子中,容器能够容纳的最大水量为 49。 -
输入:
[1, 1]
输出:1
提示:
n == height.length
2 <= n <= 10^5
0 <= height[i] <= 10^4
题解
可以盛水的量为s= min(h1, h2)*w
其中 h1 为左容器边,h2为右容器边,w则为底的宽度。
核心思想是针对现有容器,你应该是去移动比较矮的边,试图找到一个更高的边,来替代矮边才可以找到更大的容器作为现有容器。
下面是我自己写的,非常复杂。
class Solution {
public int maxArea(int[] height) {
int left = 0;
int right = height.length-1;
int heightOfPool = Math.min(height[left], height[right]);
int max = heightOfPool*(right-left);
while(left<right){
if(height[left]<height[right]){
while(left<right){
left++;
heightOfPool = Math.min(height[left], height[right]);
if(heightOfPool*(right-left)>max) {
max = heightOfPool*(right-left);
break;
}
}
}else{
while(left<right){
right--;
heightOfPool = Math.min(height[left], height[right]);
if(heightOfPool*(right-left)>max) {
max = heightOfPool*(right-left);
break;
}
}
}
}
return max;
}
}
看了蜜糖之后 简化了代码 也就是把上面中的一部分代码,如下,给优化了一下。
heightOfPool = Math.min(height[left], height[right]);
if(heightOfPool*(right-left)>max) {
max = heightOfPool*(right-left);
break;
}
class Solution {
public int maxArea(int[] height) {
int left = 0;
int right = height.length-1;
int res = 0;
int area;
while(left<right){
area = Math.min(height[left], height[right])*(right-left);
res = Math.max(res,area);
if(height[left]<height[right]){
left ++;
}else{
right --;
}
}
return res;
}
}