LeetCode刷题笔记---数组

1. 两数之和

  1. 题目描述

给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。
你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。
给定 nums = [2, 7, 11, 15], target = 9
因为 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]

  1. 思路
  1. 暴力求解,循环2次,时间复杂度为O(n2)
  2. 使用HashMap,key为target-当前遍历的值,value为遍历的当前值;hashmap的key包含当遍历的值时,输出对应的key-value
  1. 代码实现
public class Q1_两数之和 {
     
    public static void main(String[] args) {
     
        int[] nums = {
     2, 5, 5, 15};
        int target = 10;
        int[] sum = twoSum(nums, target);
        int[] sum1 = twoSum1(nums, target);
        System.out.println(Arrays.toString(sum));
        System.out.println(Arrays.toString(sum1));
    }

    public static int[] twoSum(int[] nums, int target) {
     
        int[] res = new int[2];
        for (int i = 0; i < nums.length; i++) {
     
            for (int j = i+1; j < nums.length; j++) {
     
                if(nums[i] + nums[j] == target){
     
                    res[0] = i;
                    res[1] = j;
                }
            }
        }
        return res;
    }

    public static int[] twoSum1(int[] nums, int target){
     
        int[] res = new int[2];
        HashMap<Integer, Integer> map = new HashMap<>();
        for (int i = 0; i < nums.length; i++) {
     
            if(map.containsKey(nums[i])){
     
                res[0] = map.get(nums[i]);
                res[1] = i;
            }else{
     
                map.put(target-nums[i], i);
            }
        }
        return res;
    }
}

4. 寻找两个正序数组的中位数

  1. 题目描述

给定两个大小为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。
请你找出这两个正序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n))。
你可以假设 nums1 和 nums2 不会同时为空。
nums1 = [1, 3]、nums2 = [2];则中位数是 2.0
nums1 = [1, 2]、nums2 = [3, 4];则中位数是 (2 + 3)/2 = 2.5

  1. 思路

利用归并排序将两个数组排序,然后找到中位数

  1. 代码实现
public class Q4_寻找两个正序数组的中位数 {
     
    public static void main(String[] args) {
     
        int[] nums1 = {
     1,3,4,7,8,9};
        int[] nums2 = {
     2,3,4,6,7,8};
        double medianSortedArrays = findMedianSortedArrays(nums1, nums2);
        System.out.println(medianSortedArrays);
    }

    public static double findMedianSortedArrays(int[] nums1, int[] nums2) {
     
        double res;
        if(nums1 == null){
     
            res = nums2[nums2.length / 2];
            return res;
        }
        if(nums2 == null){
     
            res = nums1[nums1.length / 2];
            return res;
        }
        ArrayList<Integer> list = new ArrayList<>();
        int length = nums1.length + nums2.length;
        int l1 = 0;
        int l2 = 0;
        while (l1 < nums1.length && l2 < nums2.length){
     
            if(nums1[l1] <= nums2[l2]){
     
                list.add(nums1[l1]);
                l1++;
            }else{
     
                list.add(nums2[l2]);
                l2++;
            }
        }
        while (l1 == nums1.length && l2 < nums2.length){
     
            list.add(nums2[l2]);
            l2++;
        }
        while (l2 == nums2.length && l1 < nums1.length){
     
            list.add(nums1[l1]);
            l1++;
        }
        if(length % 2 == 0){
     
            res = (list.get(list.size()/2 - 1) + list.get(list.size()/2)) / 2.0;
        }else{
     
            res = list.get(list.size()/2);
        }
        return res;
    }
}

11. 盛最多水的容器

  1. 题目描述

给定 n 个非负整数 a1,a2,…,an,每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0)。
找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
说明:你不能倾斜容器,且 n 的值至少为 2。
图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。
示例:
输入: [1,8,6,2,5,4,8,3,7] 输出: 49
LeetCode刷题笔记---数组_第1张图片

  1. 思路
  1. 暴力求解
  2. 使用两个指针;分别指向头和尾,由于面积等于两个下标的差乘以较小的高,所以每次移动小的那根
  1. 代码实现
public class Q11_盛最多水的容器 {
     
    public static void main(String[] args) {
     
        int[] height = {
     1,11,8,6,2,5,4,8,3,7,1,8,6,2,5,4,8,3,7,1,8,6,2,5,4,8,3,7};
        int area1 = maxArea1(height);
        System.out.println(area1);
    }

    //暴力匹配
    public static int maxArea(int[] height) {
     
        int area = 0;
        if(height.length < 2){
     
            return -1;
        }
        //i表示底的长度,j表示遍历数组下标
        for (int i=height.length-1; i>=1; i--){
     
            for (int j=0; j<height.length-i; j++){
     
                area= Math.max(i * Math.min(height[j + i], height[j]), area);
            }
        }
        return area;
    }

    public static int maxArea1(int[] height){
     
        int area = 0;
        int left = 0;
        int right = height.length -1;
        while (left < right){
     
            area = Math.max(area, (right-left)*Math.min(height[left], height[right]));
            int r = height[left] <= height[right] ? left++ : right--;
        }
        return area;
    }
}

15. 三数之和

  1. 题目描述

给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组。
注意:答案中不可以包含重复的三元组。
例如, 给定数组 nums = [-1, 0, 1, 2, -1, -4],
满足要求的三元组集合为:
[
[-1, 0, 1],
[-1, -1, 2]
]

  1. 思路

将数组排序,然后遍历数组
在遍历每一位时,使用两个指针,一个指向当前位的下一位,另一个指向最后一位,然后移动两个指针使两个数的和等于0-arr[i]

  1. 代码实现
public class Q15_三数之和 {
     
    public static void main(String[] args) {
     
        int[] nums = {
     -1,0,1,2,-1,4};
        List<List<Integer>> lists = threeSum(nums);
        for(List list: lists){
     
            System.out.println(list);
        }
    }

    public static List<List<Integer>> threeSum(int[] nums) {
     
        List<List<Integer>> lists = new ArrayList<>();
        //先判断数组长度是否大于3,小于3直接返回
        if(nums.length<3){
     
            return lists;
        }
        //对数组进行了排序
        Arrays.sort(nums);
        for (int i = 0; i < nums.length; i++) {
     
            //如果当前数大于0,则后面的数也都大于0,不可能和为0
            if(nums[i]>0){
     
                break;
            }
            //如果当前i的值与前一个相同,跳过这个i
            if(i>0 && nums[i]==nums[i-1]){
     
                continue;
            }
            //左指针指向i的后一个
            int l = i+1;
            //右指针指向最后一个
            int r = nums.length-1;
            //满足左<右
            while(l<r){
     
                int res = nums[i]+nums[l]+nums[r];
                if(res == 0){
     
                    lists.add(Arrays.asList(nums[i],nums[l],nums[r]));
                    //去重
                    while(l<r && nums[l]==nums[l+1]){
     
                        l++;
                    }
                    while(l<r && nums[r]==nums[r-1]){
     
                        r--;
                    }
                    //移动左右指针继续找
                    l++;
                    r--;
                }else if(res<0){
     
                    l++;
                }else if(res>0){
     
                    r--;
                }
            }
        }
        return lists;
    }
}

16. 最接近的三数之和

  1. 题目描述

给定一个包括 n 个整数的数组 nums 和 一个目标值 target。找出 nums 中的三个整数,使得它们的和与 target 最接近。
返回这三个数的和。假定每组输入只存在唯一答案。
例如,给定数组 nums = [-1,2,1,-4], 和 target = 1.
与 target 最接近的三个数的和为 2. (-1 + 2 + 1 = 2).

  1. 思路

类似于上一题,只是需要记录一个最小值,不需要保存所有结果

  1. 代码实现
public class Q16_最接近的三数之和 {
     
    public static void main(String[] args) {
     
        int[] nums = {
     -1,2,1,-4};
        int target = 1;
        int closest = threeSumClosest(nums, target);
        System.out.println(closest);
    }

    public static int threeSumClosest(int[] nums, int target) {
     
        Arrays.sort(nums);
        int res = nums[0] + nums[1] + nums[2];
        for (int i = 0; i < nums.length-1; i++) {
     
            int l = i + 1;
            int r = nums.length-1;
            while(l < r){
     
                int sum = nums[i] + nums[l] + nums[r];
                if(Math.abs(sum-target) < Math.abs(res-target)){
     
                    res = sum;
                }
                if(sum > target){
     
                    r--;
                }else if(sum < target){
     
                    l++;
                }else{
     
                    return res;
                }
            }
        }
        return res;
    }
}

18. 四数之和

  1. 题目描述

给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在四个元素 a,b,c 和 d
使得 a + b + c + d 的值与 target 相等?找出所有满足条件且不重复的四元组。
注意:
答案中不可以包含重复的四元组。
示例:
给定数组 nums = [1, 0, -1, 0, -2, 2],和 target = 0。
满足要求的四元组集合为:
[
[-1, 0, 0, 1],
[-2, -1, 1, 2],
[-2, 0, 0, 2]
]

  1. 思路

可以转化为三数之和

  1. 代码实现
public class Q18_四数之和 {
     
    public static void main(String[] args) {
     
        int[] nums = {
     0,0,0,0};
        List<List<Integer>> lists = fourSum(nums, -13);
        for (List<Integer> list : lists) {
     
            System.out.println(list);
        }
    }

    public static List<List<Integer>> fourSum(int[] nums, int target) {
     
        ArrayList<List<Integer>> res = new ArrayList<>();
        if(nums==null || nums.length<4) return res;
        Arrays.sort(nums);
        for (int a = 0; a < nums.length - 3; a++) {
     
            //去重
            if(a>0 && nums[a]==nums[a-1]){
     
                continue;
            }
            //当前元素可以组成的最小/大值比target大/小,则直接比较下一个值
            if(nums[a] + nums[a+1] + nums[a+2] + nums[a+3] > target
                    || nums[a] + nums[nums.length-1] + nums[nums.length-2] + nums[nums.length-3] < target){
     
                continue;
            }
            //当前元素的下一个值
            for (int b = a+1; b < nums.length - 2; b++) {
     
                //去重
                if(b > a+1 && nums[b] == nums[b-1]){
     
                    continue;
                }
                //可以组成的最小/大值比target大/小,则直接比较下一个值
                if(nums[a] + nums[b] + nums[nums.length-1] + nums[nums.length-2] < target
                        || nums[a] + nums[b] + nums[b+1] + nums[b+2] > target){
     
                    continue;
                }
                int c = b+1;
                int d = nums.length-1;
                while(c < d){
     
                    if(nums[a] + nums[b] + nums[c] + nums[d] == target){
     
                        res.add(Arrays.asList(nums[a],nums[b],nums[c],nums[d]));
                        c++;
                        while(c < d && nums[c] == nums[c-1]){
     
                            c++;
                        }
                        d--;
                        while(c < d && b < d && nums[d] == nums[d+1]){
     
                            d--;
                        }
                    }else if(nums[a] + nums[b] + nums[c] + nums[d] > target){
     
                        d--;
                    }else{
     
                        c++;
                    }
                }
            }
        }
        return res;
    }
}

26. 删除排序数组中的重复项

  1. 题目描述

给定一个排序数组,你需要在 原地 删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。
不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。
给定数组 nums = [1,1,2],
函数应该返回新的长度 2, 并且原数组 nums 的前两个元素被修改为 1, 2。
你不需要考虑数组中超出新长度后面的元素。
nums 是以“引用”方式传递的。也就是说,不对实参做任何拷贝
int len = removeDuplicates(nums);
在函数里修改输入数组对于调用者是可见的。
根据你的函数返回的长度, 它会打印出数组中该长度范围内的所有元素。
for (int i = 0; i < len; i++) {
print(nums[i]);
}

  1. 思路

两个指针,一个用来遍历数组,另一个用来找到与当前不同的第一个数,然后交换

  1. 代码实现
public class Q26_删除排序数组中的重复项 {
     
    public static void main(String[] args) {
     
        int[] arr = {
     0,0,1,1,1,2,2,3,3,4};
        System.out.println(removeDuplicates(arr));
    }

    public static int removeDuplicates(int[] nums) {
     
        if(nums == null || nums.length == 0) return 0;
        if(nums.length == 1) return 1;
        int i = 0;
        int j = 1;
        while (j < nums.length){
     
            if (nums[j] == nums[i]){
     
                j++;
            }else{
     
                //将不同的第一个数与相同的第一个数交换
                nums[++i] = nums[j++];
            }
        }
        return i+1;
    }
}

27. 移除元素

  1. 题目描述

给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。
不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
给定 nums = [3,2,2,3], val = 3,
函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。
你不需要考虑数组中超出新长度后面的元素。

  1. 思路
  1. 使用两个指针,将与val相同的数与第一个不同的数交换,最后还要遍历数组找到不为val的最后一个下标
  2. 使用两个指针,指向头和尾,将头开始遍历的与val相同的和从尾开始遍历的不同的数交换,返回头遍历的下标
  1. 代码实现
public class Q27_移除元素 {
     
    public static void main(String[] args) {
     
        int[] arr = {
     2,2};
        int i = removeElement1(arr, 2);
        System.out.println(i);
    }

    public static int removeElement(int[] nums, int val) {
     
        if(nums == null || nums.length == 0 || (nums.length == 1 && nums[0] == val)) return 0;
        for (int i = 0; i < nums.length; i++) {
     
            if(nums[i] == val){
     
                for (int j = i+1; j < nums.length; j++) {
     
                    if(nums[j] != val){
     
                        int temp = nums[i];
                        nums[i] = nums[j];
                        nums[j] = temp;
                    }
                }
            }
        }
        //System.out.println(Arrays.toString(nums));
        int i;
        for (i = 0 ; i < nums.length; i++) {
     
            if(nums[i] == val){
     
                break;
            }
        }
        return i;
    }

    public static int removeElement1(int[] nums, int val){
     
        if(nums == null || nums.length == 0 || (nums.length == 1 && nums[0] == val)) return 0;
        int left = 0;
        int right = nums.length - 1;
        while (left <= right){
     
            if(nums[left] == val){
     
                if(nums[right] != val){
     
                    nums[left] ^= nums[right];
                    nums[right] ^= nums[left];
                    nums[left] ^= nums[right];
                }
                right--;
            }else{
     
                left++;
            }
        }
        //System.out.println(Arrays.toString(nums));
        return left;
    }
}

31. 下一个排列

  1. 题目描述

实现获取下一个排列的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列。
如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列)。
必须原地修改,只允许使用额外常数空间。
以下是一些例子,输入位于左侧列,其相应输出位于右侧列。
1,2,3 → 1,3,2
3,2,1 → 1,2,3
1,1,5 → 1,5,1

  1. 思路

先在数组中从后往前找到第一对逆序对,该逆序对后面的数一定是最大的排列
从数组的最后一位开始,找到第一个比逆序对中前面的数大的数,并交换两数
从逆序对前面那一位的下标开始将数组后面的数反转,则后面的数会由最大变成最小
反转过后的数组即结果

  1. 代码实现
public class Q31_下一个排列 {
     
    public static void main(String[] args) {
     
        int[] nums = {
     1,1};
        nextPermutation(nums);
        System.out.println(Arrays.toString(nums));
    }

    public static void nextPermutation(int[] nums) {
     
        if(nums == null || nums.length == 0 || nums.length == 1) {
     
            return;
        }
        int i = nums.length - 2;
        //先在数组中从后往前找到第一对逆序对
        while (i >= 0 && nums[i] >= nums[i+1]) {
     
            i--;
        }
        if(i >= 0) {
     
            int j = nums.length - 1;
            //找到第一个比逆序对中前面的数大的数
            while (j >= 0 && nums[j] <= nums[i]) {
     
                j--;
            }
            //交换
            swap(nums, i, j);
        }
        //反转
        reverse(nums, i+1);
    }

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

    private static void reverse(int[] nums, int start){
     
        int i = start;
        int j = nums.length - 1;
        while (i < j){
     
            swap(nums, i, j);
            i++;
            j--;
        }
    }
}

41. 缺失的第一个正数

  1. 题目描述

给你一个未排序的整数数组,请你找出其中没有出现的最小的正整数。
示例 1:
输入: [1,2,0]
输出: 3
示例 2:
输入: [3,4,-1,1]
输出: 2
示例 3:
输入: [7,8,9,11,12]
输出: 1

  1. 思路

使用一个辅助数组help[nums.length+2],大小为数组长度+1,记录所出现的数字
小于0的数记录到help[0],大于数组长度的数记录到help[nums.length+1]
遍历help数组,从第2位开始,第一个为0的数即结果

  1. 代码实现
public class Q41_缺失的第一个正数 {
     
    public static void main(String[] args) {
     
        int[] nums = {
     7,8,9,11,12};
        int missingPositive = firstMissingPositive(nums);
        System.out.println(missingPositive);
    }

    public static int firstMissingPositive(int[] nums) {
     
        int[] help = new int[nums.length + 2];
        for (int i = 0; i < nums.length; i++) {
     
            if(nums[i] > nums.length){
     
                help[nums.length+1]++;
            }else if(nums[i] <= 0){
     
                help[0]++;
            } else{
     
                help[nums[i]]++;
            }
        }
        //System.out.println(Arrays.toString(help));
        for (int i = 1; i < help.length; i++) {
     
            if(help[i] == 0){
     
                return i;
            }
        }
        return help[help.length-1];
    }
}

  1. 题目描述
  1. 思路
  1. 代码实现

你可能感兴趣的:(leetcode,算法,数据结构,java)