秋招冲刺算法
双指针
常⻅的双指针有两种形式,⼀种是对撞指针,⼀种是左右指针。
快慢指针
- 基本思想:使用两个移动速度不同的指针在数组或链表等序列结构上移动。
- 通常处理结构类型:环形链表或数组。
int slow = 0,fast = 0;
while(fast < length){//相当于right走了一遍,查到分类1的就放到前面。而结束的时候刚好left的下标就是最后一个分类1
//right指向分类1的情况
if(arr[right] != 分类2){
swap(arr[left],arr[right]);
left++;
}
right++;
}
1.移动零
class Solution {
//分类1 :>0的数
//分类2 :==0的数
public void moveZeroes(int[] nums) {
int left = 0;
int right =0;
while(right<nums.length){//这里的分类1 就是>0的数
if(nums[right]!=0){//当right指向 >0 的数的时候,进行交换
swap(nums,left,right);
left++;
}
right++;
}
}
public void swap(int[] nums,int left,int right){
int temp = nums[left];
nums[left] = nums[right];
nums[right] = temp;
}
}
2.快排核心代码
public void pointerQuicklySort(int[] arr) {
pointerQuicklySort(arr, 0, arr.length - 1);
}
private void pointerQuicklySort(int[] arr, int left, int right) {
if (right<=left) return ;
int root = pointer(arr, left, right);
pointerQuicklySort(arr, root + 1, right);
pointerQuicklySort(arr, left, root - 1);
}
private int pointer(int[] arr, int left, int right) {
int slow = left + 1;//慢指针
while(fast<=right){
if(arr[fast]<arr[left]){
swap(nums,fast,slow);
slow++;
}
fast++;
}
swap(arr, left, slow - 1);//因为到最后slow在带交换的位置上,这位置上的值是大于arr[left]的
return slow-1;//注意这里也需要slow-1,因为slow位置是基应处位置的右边
}
3.复写零
解法:双指针算法,现根据“异地”操作,再优化成“就地”操作。
class Solution {
public void duplicateZeros(int[] arr) {
//1.定位 fast和slow位置
//都从-1开始,让最后的结果互相对应,fast刚好为slow位置匹配的最后一个数字
int fast = -1, slow = -1;
while (fast < arr.length-1) {
if (arr[slow+1] == 0) {
slow++;
fast += 2;
} else {
slow++;
fast++;
}
}
//1.5特殊情况判断
//如果这时候slow==0,那么fast位置就会为 arr.length。对这种情况进行处理
if(fast==arr.length){
arr[fast-1]=0;
slow--;
fast-=2;
}
//2.开始复写
while(slow>=0){
if(arr[slow]==0){
arr[fast]=0;
arr[fast-1]=0;
fast-=2;
slow--;
}else{
arr[fast]=arr[slow];
fast--;
slow--;
}
}
}
}
4.快乐数
按照这个题目走一定会形成环的:int 能形成的最大的数 也不超过 81*10=810 ,一共就有那么多数,但是这种会一直循环无数次,所以一定会产生环,即便这个环只有一个值。
思考方向:判断链表是否有环,使用快慢指针
class Solution {
public boolean isHappy(int n) {
int fast = n;int slow = n;
fast = math(fast);
while(fast!=slow){
fast = math(fast);
fast = math(fast);
slow = math(slow);
}
if(slow==1){
return true;
}else{
return false;
}
}
//写一个函:它每个位置上的数字的平方和
public int math(int n){
int ret = 0;
while(n>0){
int a = n%10;
ret+=a*a;
n/=10;
}
return ret;
}
}
左右针
-
基本思想:从两端向中间移动。⼀个指针从最左端开始,另⼀个从最右端开始,然后逐渐往中间逼近。
-
通常处理结构类型:⼀般⽤于顺序结构中,也称左右指针。
1.盛最多水的容器
import java.util.*;
class Solution {
public int maxArea(int[] arr) {
int left = 0,right = arr.length-1;
int max = 0;
while(right>left){
max = Math.max(eara(arr,left,right),max);
if(arr[left]>arr[right]){
right--;
}else{
left++;
}
}
return max;
}
public int eara(int arr[],int left,int right){
int w = right-left;
int h = arr[right]<arr[left]?arr[right]:arr[left];
return w*h;
}
}
2.剑指 Offer 57. 和为s的两个数字
https://leetcode.cn/problems/he-wei-sde-liang-ge-shu-zi-lcof/
3.三数之和
https://leetcode.cn/problems/3sum/
class Solution {
//大致思路:固定一个数,剩余的进行 左右指针找
public List<List<Integer>> threeSum(int[] nums) {
int left,right;
List<List<Integer>> ret = new ArrayList<>();
//1.先进行排序
Arrays.sort(nums);
//2.固定一个数
for(int i=0;i<nums.length;i++){
//当固定的数 为正数的时候,后面的就没必要判断了
//因为 无论多少个正数想加都还是正数
if(nums[i]>0){break;}
left = i+1;
right = nums.length-1;
while(right>left){
if(nums[left]+nums[right]+nums[i] == 0){
//System.out.println(nums[left]+" "+nums[right]+" "+nums[i]);
List<Integer> list = new ArrayList<>();
list.add(nums[i]);
list.add(nums[left]);
list.add(nums[right]);
ret.add(list);
left++;right--;
//找到之后要进行去重
//找到之后:重复的都是复合条件的,已经符合的数直接删掉即可
//左右去重:[0,0,0,0]
while(right>left && nums[right] == nums[right+1]){
right--;
}
while(right>left && nums[left] == nums[left-1]){
left++;
}
}else if(nums[left]+nums[right]+nums[i] > 0){
right--;
}else{
left++;
}
}
//根去重:[-1,-1,0,1,2]
while(i<nums.length-1&&nums[i+1] == nums[i]){
i++;
}
}
return ret;
}
}
4.四数之和
https://leetcode.cn/problems/4sum/
class Solution {
public List<List<Integer>> fourSum(int[] nums, int target) {
Arrays.sort(nums);
List<List<Integer>> ret = new LinkedList<>();
int left,right;
for(int i=0;i<nums.length-1;i++){
for(int j=i+1;j<nums.length-1;j++){
left = j+1;
right = nums.length-1;
while(right>left){
//注意int 越界的情况 还强制转换成 long
if((long)nums[i]+nums[j]+nums[left]+nums[right] == (long)target){
List<Integer> list = new LinkedList<>();
list.add(nums[i]);
list.add(nums[j]);
list.add(nums[left]);
list.add(nums[right]);
ret.add(list);
while(right>left && nums[left+1]==nums[left]){
left++;
}
while(right>left && nums[right-1]==nums[right]){
right--;
}
left++;
right--;
}else if(nums[i]+nums[j]+nums[left]+nums[right] > target){
right--;
}else{
left++;
}
}
while(j<nums.length-2 && nums[j+1] == nums[j]){j++;}
}
while(i<nums.length-2 && nums[i+1] == nums[i]){i++;}
}
return ret;
}
}