Daily_Algorithm

本文最后更新于:2 年前

每日刷题

leetcode每日刷题,先定个小目标300

项目地址

高级算法分析与设计课程作业

作业一

两数之和(力扣第1题)

给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。

你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。

示例:

给定 nums = [2, 7, 11, 15], target = 9

因为 nums[0] + nums[1] = 2 + 7 = 9

所以返回 [0, 1]

来源:力扣(LeetCode)

链接:https://leetcode-cn.com/problems/two-sum

  • 思路一:暴力,二重循环搜索答案,肯定超时
  • 思路二:使用hash表,将遍历过的数据放入hash表中,<key , value> 为<nums[i], i>结构
public int[] twoSum(int[] nums, int target) {
    HashMap<Integer, Integer> map = new HashMap<>();
    for (int i = 0; i < nums.length; i++) {
        if(map.containsKey(target - nums[i])){
            return new int[]{map.get(target - nums[i]), i};
        }
        map.put(nums[i], i);
    }
    return null;
}

最大子序和(力扣53题)

给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

示例:

输入: [-2,1,-3,4,-1,2,1,-5,4],

输出: 6

解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。

来源:力扣(LeetCode)

链接:https://leetcode-cn.com/problems/maximum-subarray

思路:动态规划

  • 创建dp数组,dp[i]表示遍历到i时,第 i个数结尾的 连续子数组的最大和

  • 动态转移方程

    dp[i] = max(dp[i - 1] + nums[i], nums[i]);
  • 初始化dp

    dp[0] = nums[0]
  • 遍历顺序为从前向后

public int maxSubArray(int[] nums) {
    // int sum = nums[0];
    // int[] dp = new int[nums.length];
    // dp[0] = nums[0];
    // for (int i = 1; i < nums.length; i++) {
    //     dp[i] = Math.max(dp[i-1] + nums[i], nums[i]);
    //     if(dp[i] > sum){
    //         sum = dp[i];
    //     }
    // }
    // return sum;
    // 可以不使用dp数组,节省空间
    int sum = nums[0];
    int result = sum;
    for (int i = 1; i < nums.length; i++) {
        sum = Math.max(sum + nums[i], nums[i]);
        if(sum > result){
            result = sum;
        }
    }
    return result;
}

多数元素(力扣169题)

给定一个大小为 n 的数组,找到其中的多数元素。多数元素是指在数组中出现次数大于 ⌊ n/2 ⌋ 的元素。

你可以假设数组是非空的,并且给定的数组总是存在多数元素。

示例 1:

输入: [3,2,3]

输出: 3

示例 2:

输入: [2,2,1,1,1,2,2]

输出: 2

来源:力扣(LeetCode)

链接:https://leetcode-cn.com/problems/majority-element

  • 思路一:使用hash表,遍历数组并计数即可
  • 思路二:排序,题中说了总是存在多数元素,那么排序后的弟⌊ n/2 ⌋即为所求答案
  • 思路三:从第一个数开始count=1,遇到相同的就加1,遇到不同的就减1,减到0就重新换个数开始计数,总能找到最多的那个
// 思路一
public int majorityElement(int[] nums) {
    HashMap<Integer, Integer> count = new HashMap<>();
    for (int i = 0; i < nums.length; i++) {
        count.put(nums[i], count.getOrDefault(nums[i], 0) + 1);
    }

    Set<Map.Entry<Integer, Integer>> entries = count.entrySet();
    for (Map.Entry<Integer, Integer> entry : entries) {
        if(entry.getValue() > nums.length / 2){
            return entry.getKey();
        }
    }
    return -1;
}
// 思路二
public int majorityElement(int[] nums) {
    Arrays.sort(nums);
    return nums[nums.length / 2];
}
// 思路三
public int majorityElement(int[] nums) {
    int res = nums[0];
    int count = 1;
    for (int i = 1; i < nums.length; i++) {
        if(nums[i] == res){
            count ++;
        }else {
            count --;
            if(count == 0){
                res = nums[i + 1];
            }
        }
    }
    return res;
}

二分查找(力扣704题)

给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。

示例 1:

输入: nums = [-1,0,3,5,9,12], target = 9

输出: 4

解释: 9 出现在 nums 中并且下标为 4

示例 2:

输入: nums = [-1,0,3,5,9,12], target = 2

输出: -1

解释: 2 不存在 nums 中因此返回 -1

来源:力扣(LeetCode)

链接:https://leetcode-cn.com/problems/binary-search-

无需多言

public int search(int[] nums, int target) {
    if(nums == null || nums.length == 0){
        return -1;
    }

    int left = 0;
    int right = nums.length - 1;
    int mid = left + (right - left) / 2;
    while (left <= right){
        if(target > nums[mid]){
            left = mid + 1;
        }else if(target < nums[mid]){
            right = mid -1;
        }else {
            return mid;
        }
        mid = left + (right - left) / 2;
    }

    return -1;
}

数组中第k个最大元素(力扣215题)

在未排序的数组中找到第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。

示例 1:

输入: [3,2,1,5,6,4] 和 k = 2

输出: 5

示例 2:

输入: [3,2,3,1,2,4,5,5,6] 和 k = 4

输出: 4

说明:可以假设 k 总是有效的,且 1 ≤ k ≤ 数组的长度

来源:力扣(LeetCode)

链接:https://leetcode-cn.com/problems/kth-largest-element-in-an-array

思路一:优先队列,维护一个容量为k的优先队列(最小堆),其队首元素为最小值,当遍历完整个数组后,队首元素即为第k大的数

思路二:基于快速排序的快速选择算法

// 优先队列    
public int findKthLargest(int[] nums, int k) {
    // 第 1 大的数,下标是 len - 1;
    // 第 2 大的数,下标是 len - 2;
    // ...
    // 第 k 大的数,下标是 len - k;
    // 创建优先队列
    // 创建一个容量为k的小根堆,那么遍历整个数组的过程中维护这个小根堆,那么其根元素就是数组中第k大的数
    PriorityQueue<Integer> priorityQueue = new PriorityQueue<>(k, Comparator.comparingInt(a -> a));
    for (int i = 0; i < k; i++) {
        priorityQueue.offer(nums[i]);
    }

    for (int i = k; i < nums.length; i++) {
        Integer peek = priori
            tyQueue.peek();
        if(nums[i] > peek){
            priorityQueue.poll();
            priorityQueue.offer(nums[i]);
        }
    }
    return priorityQueue.peek();
}

// 快速选择
public int findKthLargest(int[] nums, int k) {
    // 第 1 大的数,下标是 len - 1;
    // 第 2 大的数,下标是 len - 2;
    // ...
    // 第 k 大的数,下标是 len - k;
    int len = nums.length;
    int target = len - k;

    int left = 0;
    int right = len - 1;

    while (true) {
        int pivotIndex = partition(nums, left, right);
        if (pivotIndex == target) {
            return nums[pivotIndex];
        } else if (pivotIndex < target) {
            left = pivotIndex + 1;
        } else {
            // pivotIndex > target
            right = pivotIndex - 1;
        }
    }
}

private int partition(int[] nums, int left, int right) {
    int randomIndex = left + random.nextInt(right - left + 1);
    swap(nums, left, randomIndex);
    // all in nums[left + 1..le) <= pivot;
    // all in nums(ge..right] >= pivot;
    int pivot = nums[left];
    int le = left + 1;
    int ge = right;

    while (true) {
        while (le <= ge && nums[le] < pivot) {
            le++;
        }

        while (le <= ge && nums[ge] > pivot) {
            ge--;
        }

        if (le >= ge) {
            break;
        }
        swap(nums, le, ge);
        le++;
        ge--;
    }

    swap(nums, left, ge);
    return ge;
}

private void swap(int[] nums, int index1, int index2) {
    int temp = nums[index1];
    nums[index1] = nums[index2];
    nums[index2] = temp;
}

搜索二维矩阵(力扣240题)

编写一个高效的算法来搜索 m x n 矩阵 matrix 中的一个目标值 target。该矩阵具有以下特性:

每行的元素从左到右升序排列。

每列的元素从上到下升序排列。

示例:

现有矩阵 matrix 如下:

[

[1, 4, 7, 11, 15],

[2, 5, 8, 12, 19],

[3, 6, 9, 16, 22],

[10, 13, 14, 17, 24],

[18, 21, 23, 26, 30]

]

给定 target = 5,返回 true。

给定 target = 20,返回 false。

来源:力扣(LeetCode)

链接:https://leetcode-cn.com/problems/search-a-2d-matrix-ii

思路一:题中说的很清楚是有序的矩阵,可以模仿二分搜索解决该题

思路二:image-20220924161450669

// 思路一
public boolean searchMatrix(int[][] matrix, int target) {

    for (int[] nums : matrix) {
        if(search(nums, target)){
            return true;
        }
    }
    return false;
}

public boolean search(int[] nums, int target) {
    if(nums == null || nums.length == 0){
        return false;
    }

    int left = 0;
    int right = nums.length - 1;
    int mid = left + (right - left) / 2;
    while (left <= right){
        if(target > nums[mid]){
            left = mid + 1;
        }else if(target < nums[mid]){
            right = mid -1;
        }else {
            return true;
        }
        mid = left + (right - left) / 2;
    }

    return false;
}

// 思路二
public boolean searchMatrix(int[][] matrix, int target) {
    // 从矩阵的右上角搜索 (0, matrix[0].length)
    int m = matrix[0].length;
    int n = matrix.length;
    int x = 0;
    int y = m - 1;
    while (x < n && y >= 0){
        if(target == matrix[x][y]){
            return true;
        } else if (target < matrix[x][y]) {
            y --;
        }else {
            x ++;
        }
    }
    return false;
}

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!

 目录

Copyright © 2020 my blog
载入天数... 载入时分秒...