题目:

1> 题目解析
根据题目可知相对顺序不变,并且不能开辟数组,只能对原数组进行操作。
2> 算法思路
移动零这道题可以归为一类题,这类题为数组划分或者叫数组分块。这类题的特点是给了一个数组,制定了一个规则,在这个规则下将数组划分为若干个区间。那么这道题就是划分为两个区间,一个区间全为0,一个区间全非零。这类题的解法都可以使用双指针算法解决。(此处双指针是利用数组下标充当指针)

因此刚开始使cur指向下标0,dest为非零元素的最后一个位置,将其指向下标-1。cur移动时,当遇到零时,cur不做任何处理并向右移动一位;当为非零元素时,使dest向右移动一位,交换dest和cur位置的元素。然后重复这个过程,直到cur移动到下标为数组长度。
3> 代码
class Solution {
public void moveZeroes(int[] nums) {
for(int i = 0,dest = -1;i < nums.length;i++){
if(nums[i] != 0){
dest++;
int temp = nums[i];
nums[i] = nums[dest];
nums[dest] = temp;
}
}
}
}题目;

1> 题目解析 将数组中的零重复一次,但是不能越界,且只能在当前数组进行修改,不能开辟新数组。
2> 算法思路
双指针解法:
3> 代码
class Solution {
public void duplicateZeros(int[] arr) {
int cur = 0;
int dest = -1;
while(cur < arr.length){
if(arr[cur] != 0){
dest++;
}else {
dest += 2;
}
if(dest >= arr.length-1){
break;
}
cur++;
}
if(dest == arr.length){
arr[arr.length-1] = 0;
dest -= 2;
cur--;
}
for (; cur >= 0 ; cur--) {
if(arr[cur] != 0){
arr[dest] = arr[cur];
dest--;
}else{
arr[dest] = 0;
arr[dest-1] = 0;
dest -= 2;
}
}
}
}题目:

1> 题目解析 根据定义可知取每一位的平方和最后只有两个结果,要么重复1,要么无限循环(为什么没有第三种情况一直平方下去不重复呢,此处可以用鸽巢定理进行证明)。那么可以将两种情况并为一类,最后都会循环形成一个环,只是一个环里全是1 ,一个环里数值都不一样。 这类似于链表中是否有环的问题,可以用双指针解决。
2> 算法思路
3> 代码
class Solution {
public int bitsum(int n){
int sum = 0;
while (n != 0){
int x = n%10;
sum += x*x;
n /= 10;
}
return sum;
}
public boolean isHappy(int n){
int slow = n,fast = bitsum(n);
while (slow != fast){
slow = bitsum(slow);
fast = bitsum(bitsum(fast));
}
return slow == 1;
}
}题目:


1> 题目解析 最大储水量为 两个元素坐标之差与两元素的最小值的乘积
2> 算法思路
3> 代码
class Solution {
public int maxArea(int[] height) {
int left = 0,right = height.length - 1,ret = 0;
while (left < right){
int v = Math.min(height[left],height[right]) * (right - left);
ret = Math.max(ret,v);
if(height[left] < height[right]){
left++;
}else {
right--;
}
}
return ret;
}
}题目:

1> 题目解析
从题中可知我们需要找到能够满足能够三角形的三个元组,并返回构成的个数。示例中说明如果出现重复元素,那么重复的元素不能跳过。
2> 算法思路 前提:判断是否为三角形,需要判断任意两个数是否大于第三个数,也就是(a+b > c;a+c > b;b+c > a)全部满足才可以,但是这需要判断三次。还有更简便的判断,当已知有序时,只需要判断小的两个数是否大于最大数即可(a < b < c;判断 a+b < c),因为c 是最大的,不论和谁相加都一定大于剩下的,因此只需要判断一种情况。
此时有两种情况:
动画演示:

3> 代码
class Solution {
public int triangleNumber(int[] nums) {
//先排序
Arrays.sort(nums);
int ret = 0,n = nums.length - 1;
for(int i = n; i >= 2;i--){
int left = 0,right = i - 1;
while(left < right){
if(nums[left] + nums[right] > nums[i]){
ret += right - left;
right--;
}else{
left++;
}
}
}
return ret;
}
}题目:

1> 题目解析 从题中看出数组为有序数组,那么就可以利用单调性来解决。
2> 算法思路
3> 代码
class Solution {
public int[] twoSum(int[] price, int target) {
int left = 0,right = price.length - 1;
while(left < right){
int sum = price[left] + price[right];
if(sum > target){
right--;
}else if(sum < target){
left++;
}else{
return new int[]{price[left],price[right]};
}
}
return new int[]{0};
}
}题目:

1> 题目解析 i!=j,i!=k,j!=k说明了三元组下标不能重复,也就是同一个元素不能用两次,且三元组相加后的结果应该为0。答案中不能出现重复的三元组,从示例来看,也就是[ -1,0,1 ]和[ 0,1,-1 ]只能算一个。
2> 算法思路 这道题和上面的和为S的两数相似,难的地方在于去重操作。可以先排序,这样取出来的重复三元组的里的顺序是一样的,方便去重。
此题的细节问题:
3> 代码
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> ret = new ArrayList<>();
Arrays.sort(nums);
int n = nums.length;
for(int i = 0; i < n; ){
if(nums[i] > 0) break;
int left = i + 1,right = n - 1,target = -nums[i];
while(left < right){
int sum = nums[left] + nums[right];
if(sum > target) right--;
else if(sum < target) left++;
else{
ret.add(new ArrayList<Integer>(Arrays.asList(nums[i],nums[left],nums[right])));
left++;
right--;
while(left < right && nums[left] == nums[left-1]) left++;
while(left < right && nums[right] == nums[right+1]) right--;
}
}
i++;
while(i < n && nums[i] == nums[i-1]) i++;
}
return ret;
}
}题目

1> 题目解析 这个题和上面的三数之和基本上一样,只是多了一个数。因此可以利用三数之和来解这道。
2> 算法思路 利用三数之和的方法解
细节问题: 和" 三数之和 "一样
3> 代码
class Solution {
public static List<List<Integer>> fourSum(int[] nums, int target) {
List<List<Integer>> ret = new ArrayList<>();
//1. 先排序
Arrays.sort(nums);
//2. 固定一个值
int n = nums.length;
for (int i = 0; i < n; ) {
long tempi = (long)target - nums[i];
for (int j = i + 1; j < n; ) {
long tempj = tempi - nums[j];
int left = j + 1,right = n - 1;
while (left < right){
int sum = nums[left] + nums[right];
if(sum < tempj) left++;
else if(sum > tempj) right--;
else {
ret.add(new ArrayList<Integer>(Arrays.asList(nums[i],nums[j],
nums[left],nums[right])));
left++;
right--;
while (left < right && nums[left] == nums[left-1]) left++;
while (left < right && nums[right] == nums[right+1]) right--;
}
}
j++;
while (j < n && nums[j] == nums[j-1]) j++;
}
i++;
while (i < n && nums[i] == nums[i-1]) i++;
}
return ret;
}
}结语: 本文讲述了双指针算法题目的一些解法思路,如有问题望各位大佬给出指正。