力扣刷题——双指针

有序数组的 Two Sum

力扣167

Input: numbers={2, 7, 11, 15}, target=9
Output: index1=1, index2=2

使用双指针,一个指针指向值较小的元素,一个指针指向值较大的元素。指向较小元素的指针从头向尾遍历,指向较大元素的指针从尾向头遍历。

如果两个指针指向元素的和 sum == target,那么得到要求的结果;

  • 如果 sum > target,移动较大的元素,使 sum 变小一些;
  • 如果 sum < target,移动较小的元素,使 sum 变大一些。

数组中的元素最多遍历一次,时间复杂度为 O(N)。只使用了两个额外变量,空间复杂度为 O(1)。

class Solution {
    public int[] twoSum(int[] numbers, int target) {
        int left = 0,right = numbers.length - 1;
        while (left < right){
            int sum = numbers[left] + numbers[right];
            if (sum < target){
                left++;
            }else if (sum > target){
                right--;
            }else {
                return new int[]{left + 1,right + 1};
            }
        }
        return null;
    }
}

两数平方和

力扣633

class Solution {
    public boolean judgeSquareSum(int c) {
    //sqrt(double c)方法里传入整数自动向上转型为double类型
        int right = (int) Math.sqrt(c);
        int left = 0;
        while (left <= right){
            int ans = left * left + right * right;
            if (ans < c) left++;
            else if (ans > c) right--;
            else return true;
        }
        return false;
    }
}

反转字母串中的元音字母

力扣345
注意 String 是不可变的,不能简单地交换 String 的两个字符

一般遇见字符串问题,能转成字符数组就尽量转(方便);

class Solution {
    public String reverseVowels(String s) {
        String vowels = "aeiouAEIOU";
        //StringBuilder sb = new StringBuilder(s);
        char[] chars = s.toCharArray();
        int i = 0, j = s.length() - 1;
        while (i < j) {
        //别忘了添加限制条件 i < j,contains()括号里要求charSequence,也可以 chars[i] + ""
            while (!vowels.contains(String.valueOf(chars[i])) && i < j) {
                i++;
            }
            while (!vowels.contains(String.valueOf(chars[j])) && i < j) {
                j--;
            }
            /*char temp = sb.charAt(i);
            sb.setCharAt(i, sb.charAt(j));
            sb.setCharAt(j, temp);*/
            char temp = chars[i];
            chars[i] = chars[j];
            chars[j] = temp;
            i++;
            j--;
        }
        //return sb.toString();
        return new String(chars);
    }
}

或者一个一个移动

class Solution {
    public String reverseVowels(String s) {
        String vowels = "aeiouAEIOU";
        //StringBuilder sb = new StringBuilder(s);
        char[] chars = s.toCharArray();
        int i = 0, j = s.length() - 1;
        while (i < j) {
            if(!vowels.contains(chars[i] + "")) {
                i++;
            }
            else if(!vowels.contains(chars[j] + "")) {
                j--;
            }
            /*char temp = sb.charAt(i);
            sb.setCharAt(i, sb.charAt(j));
            sb.setCharAt(j, temp);*/
            else {
                char temp = chars[i];
                chars[i] = chars[j];
                chars[j] = temp;
                i++;
                j--;
            }
        }
        //return sb.toString();
        return new String(chars);
    }
}

回文字符串

力扣680

Input: "abca"
Output: True
Explanation: You could delete the character 'c'.

在这里插入图片描述

class Solution {
    public boolean validPalindrome(String s) {
        char[] chars = s.toCharArray();
        for (int i = 0, j = s.length() - 1;i < j; i++,j--){
            if (chars[i] != chars[j]){
                return isPalindrome(chars, i + 1, j) || isPalindrome(chars, i, j - 1);
            }
        }
        return true;
    }
    private boolean isPalindrome(char[] s ,int l ,int r){
        while (l < r){
            if (s[l++] != s[r--]) return false;
        }
        return true;
    }
}

归并两个有序数组

力扣88

Input:
nums1 = [1,2,3,0,0,0], m = 3
nums2 = [2,5,6],       n = 3

Output: [1,2,2,3,5,6]
  • 双指针从后往前
class Solution {
    public void merge(int[] nums1, int m, int[] nums2, int n) {
        int mergeIndex = m + n - 1;
        int index1 = m - 1, index2 = n - 1;
        while (index1 >= 0 || index2 >= 0) {
            if (index1 < 0) {
                nums1[mergeIndex--] = nums2[index2--];
            } else if (index2 < 0) {
                nums1[mergeIndex--] = nums1[index1--];
            } else if (nums1[index1] > nums2[index2]) {
                nums1[mergeIndex--] = nums1[index1--];
            } else {
                nums1[mergeIndex--] = nums2[index2--];
            }
        }
    }
}

或者

class Solution {
    public void merge(int[] nums1, int m, int[] nums2, int n) {
        int mergeIndex = m + n - 1;
        int index1 = m - 1, index2 = n - 1;
        while (index1 >= 0 && index2 >= 0) {
            /*if (nums1[index1] > nums2[index2]) {
                nums1[mergeIndex--] = nums1[index1--];
            } else {
                nums1[mergeIndex--] = nums2[index2--];
            }*/
            nums1[mergeIndex--] = nums1[index1] > nums2[index2] ? nums1[index1--] : nums2[index2--];
        }
        // 表示将 nums2 数组从下标 0 位置开始,拷贝到 nums1 数组中,从下标 0 位置开始,长度为 index2+1
        //若是 index2 < 0,说明nums2数组已提前比完,则从nums2数组复制0个长度到nums1数组
        System.arraycopy(nums2, 0, nums1, 0, index2 + 1);
    }
}

时间复杂度 O(n+m),空间复杂度 O(1)

  • 双指针从前往后
class Solution {
    public void merge(int[] nums1, int m, int[] nums2, int n) {
        int i = 0,j = 0,k = 0;
        int[] nums1_copy = Arrays.copyOf(nums1, m);
        while (i < m && j < n){
            nums1[k++] = nums1_copy[i] < nums2[j] ? nums1_copy[i++] : nums2[j++];
        }
        if (i < m) System.arraycopy(nums1_copy, i, nums1, i + j, m - i);
        if (j < n) System.arraycopy(nums2, j, nums1, i + j, n - j);
    }
}

时间复杂度 O(n + m),空间复杂度 O(m)

环形链表

力扣141

  • 快慢指针
    我们可以假设有a和b两个指针,一个慢一个快,如果链表是有环状的,那么走的快的那个指针迟早会跟慢指针重合的
    Alt
public class Solution {
    public boolean hasCycle(ListNode head) {
        if (head == null || head.next == null) return false;
        ListNode slow = head,fast = head.next;
        while (fast != null && fast.next != null){
            if (slow == fast){
                return true;
            }
            slow = slow.next;
            fast = fast.next.next;
        }
        return false;
    }
}

或者

public class Solution {
    public boolean hasCycle(ListNode head) {
        if (head == null || head.next == null) return false;
        ListNode slow = head,fast = head;
        while (fast != null && fast.next != null){
            slow = slow.next;
            fast = fast.next.next;
            if (slow == fast){
                return true;
            }
        }
        return false;
    }
}

下面这种的思想其实就是环形链表不存在尽头, 但只用一个指针遇到真正的环形链表会陷入死循环

例如:

while(head != null){
		head = head.next;
		if(head == null) return false;
}

所以采用双指针

public class Solution {
    public boolean hasCycle(ListNode head) {
        if (head == null || head.next == null) return false;
        ListNode slow = head,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),空间复杂度 O(1)

  • 哈希表
public class Solution {
    public boolean hasCycle(ListNode head) {
        if (head == null || head.next == null) return false;
        Set<ListNode> hashset = new HashSet<>();
        while (head != null){
            if (hashset.contains(head)) return true;
            hashset.add(head);
            head = head.next;
        }
        return false;
    }
}

时间复杂度O(n),空间复杂度 O(n)

最长子序列

力扣524

Input:
s = "abpcplea", d = ["ale","apple","monkey","plea"]

Output:
"apple"

题目描述:删除 s 中的一些字符,使得它构成字符串列表 d 中的一个字符串,找出能构成的最长字符串。如果有多个相同长度的结果,返回字典序的最小字符串。

class Solution {
    public String findLongestWord(String s, List<String> d) {
        String str = "";
        for (String s1 : d) {
            if (partOfString(s, s1)){
               if (str.length() < s1.length() || str.length() == s1.length() && s1.compareTo(str) < 0) str = s1;
            }
        }
        return str;
    }
    private boolean partOfString(String s1, String s2){
        int i = 0,j = 0;
        while (i < s1.length() && j < s2.length()){
            if (s1.charAt(i) == s2.charAt(j)) j++;
            i++;
        }
        return j == s2.length();
    }
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值