双指针算法

双指针主要用于遍历数组,两个指针指向不同的元素,从而协同完成任务

1 两数之和 II - 输入有序数组

167. 两数之和 II - 输入有序数组 - 力扣(LeetCode)

双指针:一个指向最小的元素,一个指向最大的元素

sum 等于两个指针对应的值

当 sum < target 时,需要调整 sum 变大,于是左指针右移

当 sum > target 时,需要调整 sum 变小,于是右指针左移

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

2 平方数之和

633. 平方数之和 - 力扣(LeetCode)

 和 1 类似,但是注意要声明为long,防止 int 溢出

class Solution {
    public boolean judgeSquareSum(int c) {
        long left = 0;
        long right = (int) Math.sqrt(c);
        long sum = -1;

        while (left <= right) {
            sum = left * left + right * right;
            if (sum == c) {
                return true;
            } else if (sum > c) {
                right--;
            } else {
                left++;
            }
        }
        return sum == c;
    }
}

3 反转字符串中的元音字母

345. 反转字符串中的元音字母 - 力扣(LeetCode)

        左指针和右指针分别是头尾,如果两个字母都是元音(vowel),就交换他们的位置,这里用 StringBuilder 的 setCharAt
        注意的是,都是元音的话,左右指针都要进一步(左指针右移,右指针左移)

class Solution {
    public String reverseVowels(String s) {
        int left = 0;
        int right = s.length() - 1;
        StringBuilder sb = new StringBuilder(s);
        List<Character> vowel = new ArrayList<>();
        vowel.add('A');
        vowel.add('a');
        vowel.add('E');
        vowel.add('e');
        vowel.add('I');
        vowel.add('i');
        vowel.add('O');
        vowel.add('o');
        vowel.add('U');
        vowel.add('u');
        while (left <= right) {
            if (vowel.contains(sb.charAt(left)) && vowel.contains(sb.charAt(right))) {
                char temp = sb.charAt(left);
                sb.setCharAt(left, sb.charAt(right));
                sb.setCharAt(right, temp);
                left++;
                right--;
            } else if (vowel.contains(sb.charAt(left)) && !vowel.contains(sb.charAt(right))) {
                right--;
            } else if (!vowel.contains(sb.charAt(left)) && vowel.contains(sb.charAt(right))) {
                left++;
            } else {
                left++;
                right--;
            }
        }
        return sb.toString();
    }
}

4 验证回文串 II

680. 验证回文串 II - 力扣(LeetCode)

        使用双指针可以很容易判断一个字符串是否是回文(palindrome)字符串:令一个指针从左到右遍历,一个指针从右到左遍历,这两个指针同时移动一个位置,每次都判断两个指针指向的字符是否相同,如果都相同,字符串才是具有左右对称性质的回文字符串

class Solution {
    public boolean validPalindrome(String s) {
        for (int i = 0, j = s.length() - 1; i < j; i++, j--) {
            if (s.charAt(i) != s.charAt(j)) {
                return isPalindrome(s, i + 1, j) || isPalindrome(s, i, j - 1);
            }
        }
        return true;
    }

    private boolean isPalindrome(String s, int i, int j) {
        while (i < j) {
            if (s.charAt(i++) != s.charAt(j--)) {
                return false;
            }
        }
        return true;
    }
}

5 合并两个有序数组

88. 合并两个有序数组 - 力扣(LeetCode)

        双指针,从头开始,一个数组一个指针,小的就存入res数组,但是题要求存入nums1,需要对其覆盖

        同时,对于两个有序数组,有序的性质没有用上

class Solution {
    public static void merge(int[] nums1, int m, int[] nums2, int n) {
        int left = 0;
        int right = 0;
        int[] res = new int[m + n];
        int index = 0;

        while (left < m && right < n) {
            if (nums1[left] < nums2[right]) {
                res[index++] = nums1[left++];
            } else if (nums1[left] > nums2[right]) {
                res[index++] = nums2[right++];
            } else {
                res[index++] = nums1[left++];
                res[index++] = nums2[right++];
            }
        }

        if (left == m && right != n) {
            while (right < n) {
                res[index++] = nums2[right++];
            }
        } else {
            while (left < m) {
                res[index++] = nums1[left++];
            }
        }

        for (int i = 0; i < nums1.length; i++) {
            nums1[i] = res[i];
        }
    }
}

改进:

6 环形链表

141. 环形链表 - 力扣(LeetCode)

        快慢指针

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

7 通过删除字母匹配到字典里最长单词

524. 通过删除字母匹配到字典里最长单词 - 力扣(LeetCode)

        对 dictionary 先排序,这里排序使用 List 的 sort 方法,传入一个比较器,这里使用的是 方法引用 ,先对长度排序,然后按字典序排序

        对于判断子串,使用 双指针 ,如果相等,第二个指针后移

class Solution {
    public String findLongestWord(String s, List<String> dictionary) {
        dictionary.sort(((o1, o2) -> {
            if (o1.length() != o2.length()) {
                return o2.length() - o1.length();
            } else {
                return o1.compareTo(o2);
            }
        }));
        for (String stringDic : dictionary) {
            if (isSubStr(s, stringDic)) {
                return stringDic;
            }
        }
        return "";
    }

    private boolean isSubStr(String s1, String s2) {
        // 判断s2是否为s1的子串
        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();
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值