双指针法
双指针,指的是在遍历对象的过程中,不是普通的使用单个指针进行访问,而是使用两个相同方向(快慢指针)或者相反方向(对撞指针)的指针进行扫描,从而达到相应的目的。
换言之,双指针法充分使用了数组有序这一特征,从而在某些情况下能够简化一些运算。
也就是在一个数组上,使用2个指针来同时遍历数组,此时的遍历的时间复杂度为O(n)。
function fn (list) {var left = 0;var right = list.length - 1;//遍历数组while (left <= right) {left++;// 一些条件判断 和处理... ...right--;}}
以经典题为例:
给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。不要使用额外的数组空间,你必须仅使用 #card=math&code=O%281%29&id=Z5Grv) 额外空间并原地修改输入数组。元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。你不需要考虑数组中超出新长度后面的元素。力扣链接
示例 1: 给定 nums = [3,2,2,3], val = 3, 函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。 你不需要考虑数组中超出新长度后面的元素。
示例 2: 给定 nums = [0,1,2,2,3,0,4,2], val = 2, 函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。
暴力解题
很明显暴力解法的时间复杂度是#card=math&code=O%28n%5E2%29&id=D5U7O),这道题目暴力解法在leetcode上是可以过的。
// 时间复杂度:O(n^2)// 空间复杂度:O(1)class Solution {public:int removeElement(vector<int>& nums, int val) {int size = nums.size();for (int i = 0; i < size; i++) {if (nums[i] == val) { // 发现需要移除的元素,就将数组集体向前移动一位for (int j = i + 1; j < size; j++) {nums[j - 1] = nums[j];}i--; // 因为下标i以后的数值都向前移动了一位,所以i也向前移动一位size--; // 此时数组的大小-1}}return size;}};
- 时间复杂度:
#card=math&code=O%28n%5E2%29&id=LEFW4)
 - 空间复杂度:
#card=math&code=O%281%29&id=KqMOl)
 
双指针法
双指针法(快慢指针法): 通过一个快指针和慢指针在一个for循环下完成两个for循环的工作。
class Solution {public int removeElement(int[] nums, int val) {int index = 0;for(int i = 0; i < nums.length; i++) {if(nums[i] != val) {nums[index++] = nums[i];}}return index;}}
- 时间复杂度:
#card=math&code=O%28n%29&id=O6cTW)
 - 空间复杂度:
#card=math&code=O%281%29&id=wp0hV)
 
相关题目
删除排序数组中的重复项
题目描述(力扣链接)

解题方法:
相等直接赋值给上一个指针,但注意 i 从第一个开始,所以第一个应该首先加进去
class Solution {public int removeDuplicates(int[] nums) {int slowIndex = 0;int i = 1;while (i < nums.length) {if (nums[slowIndex] == nums[i]) {i++;} else {// 此处为++slowIndex,因为第一个需要加进去nums[++slowIndex] = nums[i];}}// 此处返回的是长度return slowIndex + 1;}}
移除零
题目描述(力扣链接)

解题方法:
双指针法直接得出答案
class Solution {public void moveZeroes(int[] nums) {int index = 0;for(int i = 0; i < nums.length; i++) {if(nums[i] != 0){nums[index++] = nums[i];}}// 后面依次赋0即可for(;index < nums.length; index++) {nums[index] = 0;}}}
比较含退格的字符串
题目描述(力扣链接)

解题方法:
先转化为数组,非 ’#‘ 直接将值赋值到上一个指针,如果为 ’#‘ 则将指针减一,下次赋值就会覆盖,最后截取开始到指针得字符数组。
class Solution {public boolean backspaceCompare(String s, String t) {return change(s).equals(change(t));}public static String change(String s) {int index = 0;// 先转化为数组char[] chars = s.toCharArray();for (int i = 0; i < chars.length; i++) {// 如果不为#则赋值if (chars[i] != '#') {chars[index++] = chars[i];}// 如果为#号,且index在不在第一个位置则进行回退else if(chars[i] == '#' && index != 0) {index--;}}// 注意截取,并转化为字符串return String.valueOf(chars,0,index);}}
有序数组的平方
题目描述(力扣链接)

解题方法:
方法一:
直接将所有树平方,再排序,此时时间复杂度是 #card=math&code=O%28n%20%2B%20n%5Clog%20n%29&id=Psw33)
class Solution {public int[] sortedSquares(int[] nums) {// 解法一int index = 0;for (int i = 0; i < nums.length; i++) {nums[index++] = nums[i] * nums[i];}// 使用sort自动排序Arrays.sort(nums);return nums;}}
方法二:
双指针法,时间复杂度为O(n)。
此时数组左右两边分别使用left和right指针进行平方判断,大得数字在新数组中倒序赋值 。(详细解法)
class Solution {public int[] sortedSquares(int[] nums) {// 双指针解法二int index = nums.length - 1, left = 0, right = nums.length - 1;int[] result = new int[nums.length];while (left <= right) {if (nums[left] * nums[left] > nums[right] * nums[right]) {result[index--] = nums[left] * nums[left];left++;}else {result[index--] = nums[right] * nums[right];right--;}}return result;}}
两个数字上的双指针法
两个数组的交集 II  
https://www.yuque.com/jugelizi-rxt6d/dqbihl/nam035
见题一
