双指针法(快慢指针法)在数组和链表的操作中是非常常见的,很多考察数组、链表、字符串等操作的面试题,都使用双指针法。
在面试的时候被问到一个基础算法问题:怎样在一个链表中快速找到中间的那个值?
因为没怎么刷过算法题,一问我就蒙了,我先是想c语言中的链表,但又想java里面其实并没有接触到这个概念了,只是底层的数据结构而已,我当成数组支支吾吾回答说先看链表长度然后取中间的,意外的是面试官说这也是一种解决方式,但肯定不是最优解。
完事之后我去同学寝室时一说,他们一个室友就说是不是快慢指针问题,我开始不知道快慢指针,但是一下反应过来了,我们在遍历时使用两个索引,也就是两个指针,快索引走两步时慢索引走两步,这样快索引走完时慢索引刚好在中间。
我靠!豁然开朗,这思路怎么我想不到,看来还是得刷刷算法题,下面就对我刷的一道经典快慢指针题做个笔记
力扣27.移除元素
题目要求是从一个数组里原地移除指定元素:
给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。
不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。
暴力解法就是双循环,不推荐
然后就是双指针法,慢指针指新数组的尾部,快指针遇到和指定值不相等的元素就和慢指针交换值然后往后移,同时慢指针移一步;如果遇到相等的元素就快指针自己往后移一步,最后慢指针所指的就是新数组的长度:
class Solution {
public int removeElement(int[] nums, int val) {
int left = 0;
for(int right = 0;right < nums.length;right++){
if(nums[right] != val){
nums[left] = nums[right];
left++;
}
}
return left;
}
}
力扣977.有序数组的平方
给你一个按 递增顺序 排序的整数数组 nums
,返回 每个数字的平方 组成的新数组,要求也按 递增顺序 排序。
这道题数组里面会有负数,但是数组按整体从小到大的顺序排列,简单的方法就是全部平方之后重新排序,所以优化的方式就是能不能平方的同时去往新的数组插数据。
首先从头到尾去判断肯定不行,因为有正有负,负数平方之后会有些会大于正数,但是不管正负,平方最大的只可能在数组两头,所以我们有两个指针分别指向原数组头部和尾部,比较两者平方和,谁大就把该数插入到新数组最后的空位,插入之后指针后移或前移继续比较。
class Solution {
public int[] sortedSquares(int[] nums) {
int i = 0;
int j = nums.length - 1,k = nums.length - 1;
int[] a = new int[nums.length];
while(i <= j){
if(nums[i] * nums[i] > nums[j] * nums[j]){
a[k] = nums[i] * nums[i];
i++;
k--;
}
else {
a[k] = nums[j] * nums[j];
j--;
k--;
}
}
return a;
}
}
注意这里while(i <= j)我最开始写的i != j,这样会造成数组为偶数时少算最后一个元素。