牛客编程题--必刷101之双指针篇

本文详细介绍双指针算法的应用场景及其实现方法,包括左右指针和快慢指针的使用技巧,通过实例讲解如何解决数组和链表中的常见问题。

补充知识

双指针

双指针从广义上来说,是指用两个变量在线性结构上遍历而解决的问题。狭义上说,

  • 对于数组,指两个变量在数组上相向移动解决的问题,也称为「左右指针」问题;
  • 对于链表,指两个变量在链表上同向移动解决的问题,也称为「快慢指针」问题;

左右指针

首先判断是用左右指针还是快慢指针,这个可以根据数据结构来进行选择,如果给出的是一个数组,那么可以考虑用左右指针。左右指针在数组中实际是指两个索引值,⼀般初始化为 left = 0, right =nums.length - 1 。

滑动窗口算法框架:

int	left	=	0,	right	=	0;
while	(right	<	s.size())	{`
	#增大窗口
	window.add(s[right]);				
	right++;
	while	(window	needs	shrink)	{
		//	缩⼩窗⼝								
		window.remove(s[left]);								
		left++;
		}
}

快慢指针

【主要针对的数据结构存储方式是 链表 、链表 、链表】
快慢指针⼀般都初始化指向链表的头结点 head,前进时快指针 fast 在前,慢指针 slow 在后,巧妙解决⼀些链表中的问题。

具体内容题目之前已经发过,感兴趣的小伙伴可以查看小曾带你刷leetcode–双指针篇之左右指针(一)小曾带你刷leetcode --双指针篇之快慢指针(二)

1、合并两个有序的数组

题目描述:给出一个有序的整数数组 A 和有序的整数数组 B ,请将数组 B 合并到数组 A 中,变成一个有序的升序数组

输入:
[4,5,6],[1,2,3]
返回值:
[1,2,3,4,5,6]
说明:A数组为[4,5,6],B数组为[1,2,3],后台程序会预先将A扩容为[4,5,6,0,0,0],B还是为[1,2,3],m=3,n=3,传入到函数merge里面,然后请同学完成merge函数,将B的数据合并A里面,最后后台程序输出A数组

思路:既然是两个已经排好序的数组,如果可以用新的辅助数组,那很容易我们可以借助归并排序的思想,将排好序的两个子数组合并到一起。但是这道题要求我们在数组A上面添加,那因为数组A后半部分相当于为空,则我们可以考虑逆向使用归并排序思想,从较大的开始排。对于两个数组每次选取较大的值,因此需要使用两个同时向前遍历的双指针。

具体步骤:
step 1:使用三个指针,i指向数组A的最大元素,j指向数组B的最大元素,k指向数组A空间的结尾处。
step 2:从两个数组最大的元素开始遍历,直到某一个结束,每次取出较大的一个值放入数组A空间的最后,然后指针一次往前。
step 3:如果数组B先遍历结束,数组A前半部分已经存在了,不用管;但是如果数组A先遍历结束,则需要把数组B剩余的前半部分依次逆序加入数组A前半部分,类似归并排序最后的步骤。
在这里插入图片描述
代码实现:

import java.util.*;
public class Solution {
   
   
    public void merge(int A[], int m, int B[], int n) {
   
   
        // 定义三个指针
        int i = m-1,j = n-1,index = m+n-1;
        // 满足大于0的情况
        while(i>=0 && j>=0){
   
   
            // 如果A数组大于B数组,则将A数组元素放到最末尾位置
            if(A[i]> B[j]){
   
   
                A[index--] = A[i--];
            }else{
   
   
            // 反之,将B数组放入末尾位置
                A[index--] = B[j--];
            }
        }
        // 如果A数组先遍历结束,则需要将B数组剩余部分基于逆序加入A中
        while(j>=0){
   
   
            A[index--] = B[j--];
        }
  
    }
}

2、判断是否为回文字符串

题目描述:给定一个长度为 n 的字符串,请编写一个函数判断该字符串是否回文。如果是回文请返回true,否则返回false。
字符串回文指该字符串正序与其逆序逐字符一致。

示例1
输入:“absba”
返回值:true
示例2
输入:“ranko”
返回值:false

思路:直接首尾双指针
回文字符串正向遍历与逆向遍历结果都是一样的,因此我们可以准备两个对撞指针,一个正向遍历,一个逆向遍历。

//首指针
int left = 0;
//尾指针
int right = str.length() - 1;
//首尾往中间靠 
while(left < right){
   
    
    ......
}

在这里插入图片描述

具体步骤
step 1:准备两个指针,一个在字符串首,一个在字符串尾。
step 2:在首的指针往后走,在尾的指针往前走,依次比较路过的两个字符是否相等,若是不相等则直接就不是回文。
step 3:直到两指针在中间相遇,都还一致就是回文。因为首指针到了后半部分,走过的正好是尾指针走过的路,二者只是交换了位置,比较相等还是一样的。

public boolean judge (String str) {
   
   
        // 定义首尾指针
        int left = 0,right = str.length() -1;
        while(left < right){
   
   
            if(str.charAt(left) != str.charAt(right))
                return false;
            left ++ ;
            right --;
        }
        return true;
    }

3、合并区间

题目描述:给出一组区间,请合并所有重叠的区间。
请保证合并后的区间按区间起点升序排列。

示例1
输入:[[10,30],[20,60],[80,100],[150,180]]
返回值:[[10,60],[80,100],[150,180]]
示例2
输入:[[0,10],[10,20]]
返回值:[[0,20]]

解题思路: 贪心思想

贪心思想属于动态规划思想中的一种,其基本原理是找出整体当中给的每个局部子结构的最优解,并且最终将所有的这些局部最优解结合起来形成整体上的一个最优解。

首先考虑什么样的区间可以进行合并: 交叉的区间【后一个区间的头小于前一个区间的尾】

//区间有重叠,更新结尾
if(intervals[i].start <= res.back().end) 
    res.back
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大数据之录

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值