【D25】两数之和&三数之和&下一个排列 (LC 1&15&31)

1. 两数之和

今日主题:数组

问题描述

给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素不能使用两遍。
你可以按任意顺序返回答案。

解题思路1-暴力破解法

双层for循环遍历,找到符合条件的两个数时跳出循环

代码实现1-暴力法

class Solution {
    public int[] twoSum(int[] nums, int target) {
        int size = nums.length;
        int[] result = new int[2];
        for(int i = 0; i < size; i++){
            for(int j = i + 1; j < size; j++){
                if(nums[i] + nums[j] == target){
                    result[0] = i;
                    result[1] = j;
                    break;
                }
            }
        }
        return result;
    }
}
  • 时间复杂度O(n^2)
  • 空间复杂度O(1)

解题思路2-哈希表

利用哈希表,将寻找target-nums[i]的时间复杂度缩短至O(1)

代码实现2-哈希表

class Solution {
    public int[] twoSum(int[] nums, int target) {
        int size = nums.length;
        int[] res = new int[2];

        //key为数组中元素的值,value为其下标
        HashMap map = new HashMap<>();
        for(int i = 0; i < nums.length; i++){
            Integer matchKey = target - nums[i];
            if(map.containsKey(matchKey)){
                res[0] = map.get(matchKey);
                res[1] = i;
            }else{
                map.put(nums[i], i);
            }
        }
        return res;
    }
}

15. 三数之和

问题描述

给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。

解题思路

首先,对数组进行排序;然后,用外层for循环遍历数组,取每次遍历的值为第一个元素nums[i];接着,使用双指针遍历nums[i]之后的元素。

  • 注意,为了去重,每次移动指针时要移动至下一个不相同的元素。

代码实现

class Solution {
    public List> threeSum(int[] nums) {
        int len = nums.length;
        //对数组进行排序
        Arrays.sort(nums);
     
        List> res = new LinkedList<>();

        for(int i = 0; i < len - 2; i++){
            if(i != 0 && nums[i] == nums[i - 1]){
                //保证第一个元素不重复
                continue;
            }
            int left = i + 1 ,right = len - 1;
            while(left < right){
                if(nums[left] + nums[right] < -nums[i]){
                    left++;     
                }else if(nums[left] + nums[right] > -nums[i]){
                    right--;
                }else{
                    List triple = new ArrayList(3);
                    triple.add(nums[i]);
                    triple.add(nums[left]);
                    triple.add(nums[right]);
                    res.add(triple);
                    
                    //将左指针向右移向下一个不同的值,保证第二个元素不重复
                    left++;
                    while(left < right && nums[left - 1] == nums[left]){
                        left++;
                    }

                    //将右指针向左移向下一个不同的值,保证第三个元素不重复
                    right--;
                    while(right > left && nums[right + 1] == nums[right]){
                        right--;
                    } 
                }
            }
        }

        return res;
    }
}

31. 下一个排列

问题描述

实现获取 下一个排列 的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列。
如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列)。
必须 原地 修改,只允许使用额外常数空间。

解题思路

最开始的思路是,从后向前遍历找到第一个比最后一个元素小的元素进行交换,再将目标元素之后的元素用冒泡排序算法进行升序排列。但是,始终无法通过全部的测试用例,于是看了题解。原来我错在了不应该默认将最后一个元素作为“较大数”。

  • 算法过程来自全leetcode题解区最好的题解!
    下一个排列算法

代码实现

class Solution {
    public void nextPermutation(int[] nums) {
        int len = nums.length;
        if(len < 2){
            return;
        }
        //1.从后向前遍历,找到第一个相邻升序对,nums[i]为高位的较小数
        int i = len - 2;
        while(i >= 0){
            if(nums[i] < nums[i + 1]){
                break;
            }
            i--;
        }
        //System.out.println("i="+i);

        if(i == -1 ){
            //不存在下一个更大的排列
            reverse(nums, 0, len - 1);
            return;
        }

        //2.从后向前遍历,找到最靠右的大于nums[i]的数,将其作为低位的较大数
        int j  = len - 1;
        while(j > i){
            if(nums[j] > nums[i]){
                break;
            }
            j--;
        }
        //System.out.println("j="+j);

        //3.将较大数与较小数进行交换
       swap(nums, i , j);

       //4.将nums[i]之后的元素进行逆置,升序排列
       reverse(nums, i + 1, len -1);

    }

    //将数组中[l,r]区间中的元素进行反转
    public void reverse(int[] nums, int l, int r){
        while(l < r){
            swap(nums, l++, r--);
        }
    }

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

你可能感兴趣的:(【D25】两数之和&三数之和&下一个排列 (LC 1&15&31))