算法---双指针题型(题目来源于力扣题库)

🍋双指针是什么?

在刷题之前,需要先了解什么是双指针,双指针是刷一维数组题目的算法技巧。
双指针一般可分为对碰指针和快慢指针,对碰指针指的是两个指针分别从一维数组的开始和结尾开始移动,快慢指针指的是两个指针都是从一维数组的起始位置开始移动,但一个指针每次移动的步长较少叫慢指针,一个指针每次移动的步长较多叫快指针,快慢指针步长具体多少得视题目情况而定;不过,下面的题目一般都是使用双指针中的对碰指针。

🍋1. 两数之和 II - 输入有序数组(力扣167/LeetCode167)

题目描述链接

https://leetcode.cn/problems/two-sum-ii-input-array-is-sorted/

题目特点

一维数组非递减排序。

完整代码

直接暴力破解,根据题目的意思直接解答。

public int[] twoSum(int[] numbers, int target) {
    int index1=0;
    int index2=0;
    for (int i = 0; i <numbers.length ; i++) {
        index1=i;
        for (int j = i+1; j <numbers.length ; j++) {
            index2=j;
            if (numbers[index1]+numbers[index2]==target){
                int[] arr={index1+1,index2+1};
                return arr;
            }
        }
    }
    return null;
}

双指针方法:

public int[] twoSum1(int[] numbers, int target) {
    int left=0;
    int right=numbers.length-1;
    while(left<right){
        if (numbers[left]+numbers[right]==target){
            int[] arr={left+1,right+1};
            return arr;
        }else if (numbers[left]+numbers[right]>target){
            right--;
        }else{//numbers[left]+numbers[right]<target
            left++;
        }
    }
    return null;
}
时间复杂度和空间复杂度

下面是上述两种方法的时间复杂度和空间复杂度的比较,前者是暴力破解,后者是双指针方法。

时间复杂度:O(n^2)VSO(n);

空间复杂度:O(1)VSO(1)。

因此,通过以上比较,双指针方法表现更加优秀。

🍋2. 两数平方和(力扣633/LeetCode633)

题目描述链接

https://leetcode.cn/problems/sum-of-square-numbers/

题目特点

一维数组非递减排序。

完整代码

巧用sqrt函数:

public boolean judgeSquareSum1(int c) {
    for (long i = 0; i*i <=c ; i++) {
        double b = Math.sqrt(c - i * i);
        if (b==(int)b){
            return true;
        }
    }
    return false;
}

双指针方法:

public boolean judgeSquareSum2(int c) {
    int a=0;
    int b= (int) Math.sqrt(c);
    while(a>b){
        if (a*a+b*b==c){
            return true;
        }else if (a*a+b*b>c){
            b--;
        }else{
            a++;
        }
    }
    return false;
}
时间复杂度和空间复杂度

下面是上述两种方法的时间复杂度和空间复杂度的比较,前者是巧用sqrt函数方法,后者是双指针方法。

时间复杂度:O(n)VSO(n);

空间复杂度:O(1)VSO(1)。

但整体表现双指针方法更加优秀。

🍋3. 反转字符串中的元音字符(力扣345/LeetCode345)

题目描述链接

https://leetcode.cn/problems/reverse-vowels-of-a-string/

题目特点

一维字母交换。

完整代码

双指针方法:

(力扣正解答案)

public String reverseVowels1(String s) {
    int n = s.length();
    char[] arr = s.toCharArray();
    int i = 0, j = n - 1;
    while (i < j) {
        while (i < n && !isVowel(arr[i])) {
            ++i;
        }
        while (j > 0 && !isVowel(arr[j])) {
            --j;
        }
        if (i < j) {
            swap(arr, i, j);
            ++i;
            --j;
        }
    }
    return new String(arr);
}

public boolean isVowel(char ch) {
    return "aeiouAEIOU".indexOf(ch) >= 0;
}

public void swap(char[] arr, int i, int j) {
    char temp = arr[i];
    arr[i] = arr[j];
    arr[j] = temp;
}

(自解答案)

public static  String reverseVowels(String s) {
    char[] chars = s.toCharArray();
    int left=0;
    boolean flag1=false;
    int right=chars.length-1;
    boolean flag2=false;
    while(left<=right){
        if (!(chars[left]=='a'||chars[left]=='e'||chars[left]=='i'||chars[left]=='o'||chars[left]=='u'||
                chars[left]=='A'||chars[left]=='E'||chars[left]=='I'||chars[left]=='O'||chars[left]=='U')){
            left++;
        }else{
            flag1=true;
        }
        if (!(chars[right]=='a'||chars[right]=='e'||chars[right]=='i'||chars[right]=='o'||chars[right]=='u'||
                chars[right]=='A'||chars[right]=='E'||chars[right]=='I'||chars[right]=='O'||chars[right]=='U')){
            right--;
        }else{
            flag2=true;
        }
        if (flag1&&flag2){
            char temp=chars[left];
            chars[left]=chars[right];
            chars[right]=temp;
            flag1=false;
            flag2=false;
            left++;
            right--;
        }
    }
    String x="";
    for (int i = 0; i < chars.length; i++) {
        x +=chars[i];
    }
    return x;
}
时间复杂度和空间复杂度

下面是双指针的时间复杂度和空间复杂度。

时间复杂度:O(n);

空间复杂度:O(1)。

🍋4. 回文字符串(力扣680/LeetCode680)

题目描述链接

https://leetcode.cn/problems/valid-palindrome-ii/

题目特点

一维数组回文判断,从两头走。

完整代码

双指针方法,使用该方法要注意全集和子集的保握。

public boolean validPalindrome1(String s) {
    int low = 0, high = s.length() - 1;
    while (low < high) {
        char c1 = s.charAt(low), c2 = s.charAt(high);
        if (c1 == c2) {
            ++low;
            --high;
        } else {
            return validPalindrome(s, low, high - 1) || validPalindrome(s, low + 1, high);
        }
    }
    return true;
}

public boolean validPalindrome(String s, int low, int high) {
    for (int i = low, j = high; i < j; ++i, --j) {
        char c1 = s.charAt(i), c2 = s.charAt(j);
        if (c1 != c2) {
            return false;
        }
    }
    return true;
}
时间复杂度和空间复杂度

下面是双指针方法的时间复杂度和空间复杂度。

时间复杂度:O(n);

空间复杂度:O(1)。

🍋5. 归并两个有序数组(力扣88/LeetCode88)

题目描述链接

https://leetcode.cn/problems/merge-sorted-array/

题目特点

两个一维数组,一个新的一维数组,有需要才把数组往后移动。

完整代码

直接暴力破解,先把需要的元素都放入一个数组,再对它进行排序。

public static void merge(int[] nums1, int m, int[] nums2, int n) {
    int[] arr=new int[m+n];
    for (int i = 0; i < m; i++) {
        arr[i]=nums1[i];
    }
    for (int i = 0; i < n; i++) {
        arr[m+i]=nums2[i];
    }
    Arrays.sort(arr);
    for (int i = 0; i < arr.length; i++) {
        nums1[i]=arr[i];
    }
}

双指针方法,使用该方法,类似于合并两个链表,但链表的合并更加复杂。

public void merge1(int[] nums1, int m, int[] nums2, int n) {
    int p1 = 0, p2 = 0;
    int[] sorted = new int[m + n];
    int cur;
    while (p1 < m || p2 < n) {
        if (p1 == m) {
            cur = nums2[p2++];
        } else if (p2 == n) {
            cur = nums1[p1++];
        } else if (nums1[p1] < nums2[p2]) {
            cur = nums1[p1++];
        } else {
            cur = nums2[p2++];
        }
        sorted[p1 + p2 - 1] = cur;
    }
    for (int i = 0; i != m + n; ++i) {
        nums1[i] = sorted[i];
    }
}
时间复杂度和空间复杂度

下面是上述两种方法的时间复杂度和空间复杂度的比较,前者是直接暴力破解,后者是双指针方法。

时间复杂度:O(约(n+m)^2)VSO(n);

空间复杂度:O(1)VSO(1)。

综上所述,双指针的表现更加优秀。

🍋6. 判断链表是否存在环(力扣141/LeetCode141)

题目描述链接

https://leetcode.cn/problems/linked-list-cycle/

题目特点

是否存在环问题,依然是类一维数组问题,使用快慢指针解决,以及使用哈希集合的特点来解决。

完整代码

哈希集合方法Set:

public boolean hasCycle1(ListNode head) {
    Set<ListNode> set=new HashSet<>();
    while(head!=null){
        if (!set.add(head)){
            return true;
        }
        head=head.next;
    }
    return false;
}

双指针方法,快慢指针,一个走得快,一个走得慢,但其边界条件判断需要注意。

public boolean hasCycle2(ListNode head) {
    if (head==null||head.next==null){
        return false;
    }
    ListNode slow=head;
    ListNode fast=head.next;
    while(slow!=fast){
        if (fast==null||fast.next==null){
            return false;
        }
        slow=slow.next;
        fast=fast.next.next;
    }
    return true;
}
时间复杂度和空间复杂度

下面是上述两种方法的时间复杂度和空间复杂度的比较,前者是巧用哈希集合方法,后者是双指针方法。

时间复杂度:O(n^2)VSO(n);

空间复杂度:O(1)VSO(1)。

双指针的表现更加优秀。

🍋7. 最长子序列(力扣524/LeetCode524)

题目描述链接

https://leetcode.cn/problems/longest-word-in-dictionary-through-deleting/

题目特点

两个一维数组,比较其两者是否相同,相同才进行下一步。

完整代码

双指针方法,字符串的compareTo可以判断字典序。

public String findLongestWord1(String s, List<String> dictionary) {
    String y="";
    for (String x:dictionary) {
        int l1=x.length();
        int l2=y.length();
        //字符串的compareTo可以判断字典序
        if (l2>l1 ||(l1==l2&&y.compareTo(x)<0)){
            continue;
        }
        if (isFlag(s,x)){
            y=x;
        }
    }
    return y;
}
//判断分离子串的方法
public static boolean isFlag(String s,String target){
    int i=0,j=0;
    while(i<s.length()&&j<target.length()){
        if (s.charAt(i)==target.charAt(j)){
            j++;
        }
        i++;
    }
    return j==target.length();
}
时间复杂度和空间复杂度

下面是双指针方法的时间复杂度和空间复杂度。

时间复杂度:O(n^2);

空间复杂度:O(1)。

🍋题型总结

使用条件:在一个一维数组或者两个一维数组的时候使用,一个一维数组需要满足非递减排序,两个一维数组则不需要满足非递减排序的条件。

优势:一般一维数组的题目时间复杂度都需要O(N^2),如果可以使用双指针方法,将把时间复杂度降为O(N),极大降低了时间复杂度。
在这里插入图片描述

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值