3.双指针(三)

https://leetcode-cn.com/tag/two-pointers/

题目汇总

167. 两数之和 II - 输入有序数组简单[✔]

209. 长度最小的子数组中等[✔]

234. 回文链表简单(??)

283. 移动零简单

287. 寻找重复数中等(???)

344. 反转字符串简单 [✔]

345. 反转字符串中的元音字母简单

349. 两个数组的交集简单

167. 两数之和 II - 输入有序数组简单

给定一个已按照升序排列的有序数组,找到两个数使得它们相加之和等于目标数。
函数应该返回这两个下标值index1 和 index2,其中 index1 必须小于 index2
说明:
返回的下标值(index1 和 index2)不是从零开始的。
你可以假设每个输入只对应唯一的答案,而且你不可以重复使用相同的元素。
示例:
输入: numbers = [2, 7, 11, 15], target = 9
输出: [1,2]
解释: 2 与 7 之和等于目标数 9 。因此 index1 = 1, index2 = 2 。

思路:双指针,最基础的一道题
class Solution {//执行用时 :1 ms, 在所有 Java 提交中击败了97.07%的用户
    public int[] twoSum(int[] numbers, int target) {
        int[] result = new int[2];//存放输出数组
        if(numbers == null || numbers.length < 2)
            return result;
        int i = 0;
        int j = numbers.length - 1;
        while(i < j){
            int sum = numbers[i] + numbers[j];
            if(sum == target){
                result[0] = i + 1;//下标是从1开始的,要加1
                result[1] = j + 1;
                return result;
            }else if(sum > target){
                j--;
            }
            else{
                i++;
            }

        }
    return result;
    }
}

209. 长度最小的子数组中等

给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的连续子数组,并返回其长度。如果不存在符合条件的连续子数组,返回 0。
示例:
输入: s = 7, nums = [2,3,1,2,4,3]
输出: 2
解释: 子数组 [4,3] 是该条件下的长度最小的连续子数组。
进阶:
如果你已经完成了O(n) 时间复杂度的解法, 请尝试 O(n log n) 时间复杂度的解法。

思路:双指针

设置两个指针表示一个滑动窗口,窗口中的元素小于目标值,右指针向右移,扩大窗口。窗口中的元素大于目标值,比较当前窗口大小是否为最小值,左指针向右移,缩小窗口。

class Solution {//执行用时 :2 ms, 在所有 Java 提交中击败了84.80%的用户
    public int minSubArrayLen(int s, int[] nums) {//执行用时 :2 ms
        if(nums == null || nums.length <= 0)
            return 0;
        int left = 0;
        int sum = 0;
        int min = Integer.MAX_VALUE;
        for(int right=0;right= s){
                min = Math.min(min, right - left + 1);
                sum -= nums[left++];//减小区间
            }
        }
    return min == Integer.MAX_VALUE ? 0 : min;
    }
}

234. 回文链表简单

请判断一个链表是否为回文链表。
示例 1:
输入: 1->2
输出: false
示例 2:
输入: 1->2->2->1
输出: true
进阶:
你能否用 O(n) 时间复杂度和 O(1) 空间复杂度解决此题?

思路:双指针

能想到是快慢指针,维持半条翻转链表,这不是简单的题目吧?

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {//执行用时 :1 ms, 在所有 Java 提交中击败了99.82%的用户
    public boolean isPalindrome(ListNode head) {
        if (head == null || head.next == null)
            return true;
        ListNode slow = head; 
        ListNode fast = head;
        // 根据快慢指针,找到链表的中点
        while (fast != null && fast.next != null) {
            slow = slow.next;
            fast = fast.next.next;
        }
        ListNode newHalf = reverse(slow);//翻转后半个链表
        while(newHalf != null){// 两个半长链表的比较 遍历两个半长链表
            if(head.val != newHalf.val){
                return false;
            }
            newHalf = newHalf.next;
            head = head.next;
        }
        return true;
    }

    private ListNode reverse(ListNode head) {
        // 递归到最后一个节点,返回新的新的头结点
        if (head.next == null) {
            return head;
        }
        ListNode newHead = reverse(head.next);
        head.next.next = head;
        head.next = null;
        return newHead;
    }
}

283. 移动零简单

给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
示例:
输入: [0,1,0,3,12]输出: [1,3,12,0,0]

说明:

  1. 必须在原数组上操作,不能拷贝额外的数组。
  2. 尽量减少操作次数。
思路:双指针
class Solution {//执行用时 :0 ms, 在所有 Java 提交中击败了100.00%的用户
    public void moveZeroes(int[] nums) {
        if(nums == null || nums.length < 1) {
            return;
        }
        int j = 0;
        //第一次遍历的时候,j用来记录当前有多少非0元素,把非0元素都向左移动
        for(int i=0;i

287. 寻找重复数中等

给定一个包含 n + 1 个整数的数组 nums,其数字都在 1n 之间(包括 1 和 n),可知至少存在一个重复的整数。假设只有一个重复的整数,找出这个重复的数。
示例 1:
输入: [1,3,4,2,2]
输出: 2
示例 2:
输入: [3,1,3,4,2]
输出: 3
说明:

  1. 不能更改原数组(假设数组是只读的)。
  2. 只能使用额外的 O(1) 的空间。
  3. 时间复杂度小于 O(n2) 。
  4. 数组中只有一个重复的数字,但它可能不止重复出现一次。
思路:双指针二分查找

转自链接使用二分法查找一个有范围的整数(结合抽屉原理)https://leetcode-cn.com/problems/find-the-duplicate-number/solution/er-fen-fa-si-lu-ji-dai-ma-python-by-liweiwei1419/

class Solution {//执行用时 :3 ms, 在所有 Java 提交中击败了60.20%的用户
    public int findDuplicate(int[] nums) {
        if(nums == null || nums.length < 1)
            return 0;
        int left = 0;
        int right = nums.length;
        while(left < right){
            int mid = (right - left) / 2 + left;
            int count = 0;
            for(int num:nums){
                if(num <= mid){
                    count += 1;
                }
            }
            if(count > mid){
                right = mid;
            }else{
                left = mid + 1;
            }
        }
        return left;
    }
}

344. 反转字符串简单

编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 char[] 的形式给出。
不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。
你可以假设数组中的所有字符都是 ASCII 码表中的可打印字符。
示例 1:
输入:["h","e","l","l","o"]
输出:["o","l","l","e","h"]
示例 2:
输入:["H","a","n","n","a","h"]
输出:["h","a","n","n","a","H"]

思路:双指针

设置两个首尾指针,互换元素,移动指针。

class Solution {//执行用时 :1 ms, 在所有 Java 提交中击败了99.96%的用户
    public void reverseString(char[] s) {
        if(s.length <= 0)
            return;
        int i = 0;
        int j = s.length - 1;
        while(i < j){
            char temp = s[j];
            s[j] = s[i];
            s[i] = temp;
            i++;
            j--;
        }

    }
}

345. 反转字符串中的元音字母简单

编写一个函数,以字符串作为输入,反转该字符串中的元音字母。
示例 1:
输入: "hello",输出: "holle"
示例 2:
输入: "leetcode",输出: "leotcede"
说明:
元音字母不包含字母"y"。

思路:双指针

注意大小写都要包括。

class Solution {//执行用时 :6 ms, 在所有 Java 提交中击败了44.16%的用户
    public String reverseVowels(String s) {
        if(s.length() <= 1)
            return s;  
        char[] c = s.toCharArray();
        HashSet set = new HashSet<>(Arrays.asList('a', 'e', 'i', 'o', 'u', 'A', 'E', 'I', 'O', 'U'));
        int i = 0;
        int j = s.length() - 1;
        
        while(i < j){
            while(i < j && !set.contains(c[i])){
                i++;
            }
            while(i < j && !set.contains(c[j])){
                j--;
            }
            if(c[i] != c[j]){
                char temp = c[j];
                c[j] = c[i];
                c[i] = temp;
            }
            i++;
            j--;
        }
    return new String(c);
    }
}

349. 两个数组的交集简单

给定两个数组,编写一个函数来计算它们的交集。
示例 :
输入: nums1 = [1,2,2,1], nums2 = [2,2],输出: [2]

思路:双指针

将两个数组排序,设置两个指针,分别从每个数组的第一个元素开始比较,移动指针,相等元素存入HashSet中,将set的元素写入一个新的数组中,并输出。

class Solution {//执行用时 :3 ms, 在所有 Java 提交中击败了98.09%的用户
    public int[] intersection(int[] nums1, int[] nums2) {
        if(nums1 == null || nums1.length < 0 || nums2 == null || nums2.length < 0)
            return new int[0];
        HashSet set = new HashSet<>();
        Arrays.sort(nums1);
        Arrays.sort(nums2);
        int i = 0;
        int j = 0;
        while(i < nums1.length && j < nums2.length){
            if(nums1[i] == nums2[j]){
                set.add(nums1[i]);
                i++;
                j++;
            }else if(nums1[i] < nums2[j]){
                i++;
            }else{
                j++;
            }
        }
        //将set的元素写入一个新的数组中
        int[] res = new int[set.size()];
        int index = 0;
        for(int num:set){
            res[index] = num;
            index++;
        }
    return res;
    }
}

你可能感兴趣的:(3.双指针(三))