从三个方面(后面会更新剩下的两个部分)给大家分享一下笔试中双指针考察的一些范围(有些题型面试题也喜欢考),因此建议大家对照着这些题型,学习一下~
双指针算法讲解
基础算法之一,也是笔试中比较常考的一个算法,双指针题型以及变型有很多,这里面主要列举两大类,一类是在两个数组中使用两个指针分别指向这两个数组,这一类问题中,最经典的就是判断子序列的问题,另一类则是在一个数组中使用两个指针指向这一个数组,这类问题又称为同向双指针问题,也称为滑动窗口问题,这类问题的本质其实可以理解为动态规划,比如l和r两个双指针,很多问题其实就变为以r结尾的最大值/最小值,这类问题是需要满足单调性的:当[l,r]区间不满足条件时,l指针需要左移,直到[l,r]区间满足条件为止,且当l=r时,都可以满足条件,很多时候,如果数组的数值可以取负数,是不能使用双指针来求最优解的,就是因为不满足单调性,这种题目其实比较难的是一种抽象问题的能力,有的题目需要把问题做一个转化,首先需要判断是否满足单调性,如果满足,就需要把问题转化为一个可以使用双指针去解决的一个滑动窗口问题。
题型一 多指针滑动窗口
这类题型一般是有多个数组或者字符串,然后多个指针指向不同的数组或者字符串,这类题型最经典的问题就是判断子序列问题,很多题目都可以抽象成这样一个问题。
LeetCode 392.判断子序列
题解:本题是一个多指针题型的一个模板题,可以使用两个指针分别指向字符串s和t的起始位置,如果当前位置有s[l]=t[r],则l++,r++,如果不相等,则r++,如果最终l指向字符串s的末尾位置,则说明字符串s是t的子序列。
复杂度分析
时间复杂度:O(n+m)
空间复杂度:O(1)
C++- bool isSubsequence(string s, string t) {
- int l=0,r=0;
- int n=s.size(),m=t.size();
- while(l<n&&r<m)
- {
- if(s[l]==t[r]){
- l++;
- }
- r++;
- }
- return l==n;
- }
复制代码 Java- public boolean isSubsequence(String s, String t) {
- int l = 0, r = 0;
- int n = s.length(), m = t.length();
- while (l < n && r < m) {
- if (s.charAt(l) == t.charAt(r)) {
- l++;
- }
- r++;
- }
- return l == n;
- }
复制代码 Python- def isSubsequence(s, t):
- l, r = 0, 0
- n, m = len(s), len(t)
- while l < n and r < m:
- if s[l] == t[r]:
- l += 1
- r += 1
- return l == n
复制代码 LeetCode 2410. 运动员和训练师的最大匹配数
题解:排序+双指针,对于一个运动员player来说,他应该尽可能匹配比他的数值大,且尽可能接近他的训练师trainers,如果匹配的trainers过大,会导致其他运动员可能无法匹配,因此我们可以直接把这两个数组排序,然后使用双指针模拟即可,和上面一道判断子序列的模板题的代码基本上一模一样,就是多了一个排序的代码。
复杂度分析
时间复杂度:O(nlogn)
空间复杂度:O(1)
C++- class Solution {
- public:
- int matchPlayersAndTrainers(vector<int>& players, vector<int>& trainers) {
- sort(players.begin(),players.end());
- sort(trainers.begin(),trainers.end());
- int n=players.size(),m=trainers.size();
- int l=0,r=0;
- int res=0;
- while(l<n&&r<m){
- if(players[l]<=trainers[r]){
- l++;
- res++;
- }
- r++;
- }
- return res;
- }
- };
复制代码 Java- class Solution {
- public int matchPlayersAndTrainers(int[] players, int[] trainers) {
- Arrays.sort(players);
- Arrays.sort(trainers);
- int n = players.length;
- int m = trainers.length;
- int l = 0, r = 0;
- int res = 0;
- while (l < n && r < m) {
- if (players[l] <= trainers[r]) {
- l++;
- res++;
- }
- r++;
- }
- return res;
- }
- }
复制代码 Python- class Solution:
- def matchPlayersAndTrainers(self, players, trainers):
- players.sort()
- trainers.sort()
- n = len(players)
- m = len(trainers)
- l = 0
- r = 0
- res = 0
- while l < n and r < m:
- if players[l] <= trainers[r]:
- l += 1
- res += 1
- r += 1
- return res
复制代码 2023米哈游-子序列
题解:提供一个比较容易想到的解法:使用LeetCode 392题的思想,首先去把字符串s和t的公共部分给去除掉,然后使用两个栈去存字符串s和t的剩余部分s1和s2,对于二者的剩余部分,要么为空,要么是"mhy"的子串构成的字符串,否则,则不满足条件,因此,只需要把LeetCode 392题的代码做些许调整,即可ac。
大家也可以学习一下塔子哥的做法,个人感觉比较巧妙,由于部分朋友没有购买网站的会员,所以我就截图贴一下塔子哥的文字题解~
复杂度分析
时间复杂度:O(n+m)
空间复杂度:O(n+m)
塔子哥代码- #include <bits/stdc++.h>
- using namespace std;
- int bin_s[3], bin_t[3];
- int main() {
- int T;
- cin >> T;
- while(T--) {
- bin_s[0] = bin_s[1] = bin_s[2] = 0;
- bin_t[0] = bin_t[1] = bin_t[2] = 0;
- string s, t;
- cin >> s >> t;
- string new_s, new_t;
- for(int i = 0; i < (int) s.length(); i++) {
- if(s[i] == 'm') bin_s[0]++;
- else if(s[i] == 'h') bin_s[1]++;
- else if(s[i] == 'y') bin_s[2]++;
- else new_s.push_back(s[i]);
- }
- for(int i = 0; i < (int) t.length(); i++) {
- if(t[i] == 'm') bin_t[0]++;
- else if(t[i] == 'h') bin_t[1]++;
- else if(t[i] == 'y') bin_t[2]++;
- else new_t.push_back(t[i]);
- }
- if(new_s == new_t) {
- if(bin_s[0] - bin_t[0] == bin_s[1] - bin_t[1]
- && bin_s[0] - bin_t[0] == bin_s[2] - bin_t[2])
- cout << "Yes" << endl;
- else cout << "No" << endl;
- }
- else cout << "No" << endl;
- }
- return 0;
- }
复制代码 C++- #include <bits/stdc++.h>
- using namespace std;
- string s,t;
- int T;
- bool check(string &s){
- int n=s.size();
- if(n%3){
- return false;
- }
- for(int i=0;i<n-3;i++){
- if(s.substr(i,3)!="mhy"){
- return false;
- }
- }
- return true;
- }
- void solve(){
- cin>>s>>t;
- int n=s.size(),m=t.size();
- string s1,s2;
- int l=0,r=0;
- while(l<n){
- if(s[l]==t[r]){
- l++;
- r++;
- continue;
- }
- else{
- s1.push_back(s[l++]);
- }
- }
- s2=t.substr(r);
- if(!s2.size()){
- if(check(s1)){
- puts("Yes");
- }
- else{
- puts("No");
- }
- }
- else{
- if(check(s1)){
- puts("Yes");
- }
- else{
- puts("No");
- }
- }
- }
- int main(){
- cin>>T;
- while(T--){
- solve();
- }
- return 0;
- }
复制代码 Java- import java.util.Scanner;
- public class Main {
- public static void main(String[] args) {
- Scanner scanner = new Scanner(System.in);
- int T = scanner.nextInt();
- scanner.nextLine(); // Consume the newline character
-
- while (T-- > 0) {
- String s = scanner.nextLine();
- String t = scanner.nextLine();
- int n = s.length();
- int m = t.length();
- String s1 = "";
- String s2 = "";
- int l = 0, r = 0;
- while (l < n) {
- if (s.charAt(l) == t.charAt(r)) {
- l++;
- r++;
- } else {
- s1 += s.charAt(l++);
- }
- }
- s2 = t.substring(r);
- if (s2.isEmpty()) {
- if (check(s1)) {
- System.out.println("Yes");
- } else {
- System.out.println("No");
- }
- } else {
- if (check(s1)) {
- System.out.println("Yes");
- } else {
- System.out.println("No");
- }
- }
- }
- }
- private static boolean check(String s) {
- int n = s.length();
- if (n % 3 != 0) {
- return false;
- }
- for (int i = 0; i < n - 3; i++) {
- if (!s.substring(i, i + 3).equals("mhy")) {
- return false;
- }
- }
- return true;
- }
- }
复制代码 Python- def check(s):
- n = len(s)
- if n % 3:
- return False
- for i in range(n - 2):
- if s[i:i + 3] != "mhy":
- return False
- return True
- def solve():
- s = input()
- t = input()
- n = len(s)
- m = len(t)
- s1 = ""
- s2 = ""
- l = 0
- r = 0
- while l < n:
- if s[l] == t[r]:
- l += 1
- r += 1
- else:
- s1 += s[l]
- l += 1
- s2 = t[r:]
- if not s2:
- if check(s1):
- print("Yes")
- else:
- print("No")
- else:
- if check(s1):
- print("Yes")
- else:
- print("No")
- T = int(input())
- for _ in range(T):
- solve()
复制代码 有关面试算法题题解在我的知乎专栏:面试算法题题解 - 知乎 (zhihu.com)
有关笔试真题解析的文章在我的知乎专栏:笔试真题解析 - 知乎 (zhihu.com)
有关大厂笔试的常考算法题在我知乎的置顶文章笔试刷题指南中有相关的练习题:笔试刷题指南
笔试ACM输入以及常见考点和技巧在我的知乎专栏:笔试攻略 - 知乎 (zhihu.com) |