算法题(一)

个人在秋招和春招的时候刷了一些题目,主要是来自leetcode,通过学习别人的题解和个人的尝试,整理了一些题目较优的解法,现在分享给大家,可能对你的思维方式会有一丢丢的启发

数组

1. 两数之和

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

你可以假设每种输入只会对应一个答案。但是,数组中同一个元素不能使用两遍。

你可以按任意顺序返回答案。

示例 1:

输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。

解题思路

这道题最优的做法时间复杂度是 O(n)。

顺序扫描数组,对每一个元素,在 map 中找能组合给定值的另一半数字,如果找到了,直接返回 2 个数字的下标即可。如果找不到,就把这个数字存入 map 中,等待扫到“另一半”数字的时候,再取出来返回结果。

class Solution{
    public int[] twoSum(int[] nums, int target){
        Map<Integer, Integer> map = new HashMap<>();
        for(int i = 0; i < nums.length; i++){
            int another = target - nums[i];
            if(map.containsKey(another)){
                return new int[]{map.get(another), i};
            }
            map.put(nums[i], i);
        }
        return new int[]{-1, -1};
    }
}
func twoSum(nums []int, target int) []int {
    m := make(map[int]int, 0)
    for i, v := range(nums){
        another := target - v
        if j, ok := m[another]; ok{
            return []int{j, i}
        }
        m[v] = i
    }
    return []int{-1, -1}
}

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

给定两个大小为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的中位数。

进阶:你能设计一个时间复杂度为 O(log (m+n)) 的算法解决此问题吗?

示例 1:

输入:nums1 = [1,3], nums2 = [2]
输出:2.00000
解释:合并数组 = [1,2,3] ,中位数 2

示例 2:

输入:nums1 = [1,2], nums2 = [3,4]
输出:2.50000
解释:合并数组 = [1,2,3,4] ,中位数 (2 + 3) / 2 = 2.5

示例 3:

输入:nums1 = [0,0], nums2 = [0,0]
输出:0.00000

示例 4:

输入:nums1 = [], nums2 = [1]
输出:1.00000

示例 5:

输入:nums1 = [2], nums2 = []
输出:2.00000

提示:

  • nums1.length == m
  • nums2.length == n
  • 0 <= m <= 1000
  • 0 <= n <= 1000
  • 1 <= m + n <= 2000
  • -106 <= nums1[i], nums2[i] <= 106

解题思路
给出两个有序数组,要求找出这两个数组合并以后的有序数组中的中位数。要求时间复杂度为 O(log (m+n))。

这一题最容易想到的办法是把两个数组合并,然后取出中位数。但是合并有序数组的操作是 O(max(n,m)) 的,不符合题意。看到题目给的 log 的时间复杂度,很容易联想到二分搜索。

由于要找到最终合并以后数组的中位数,两个数组的总大小也知道,所以中间这个位置也是知道的。只需要二分搜索一个数组中切分的位置,另一个数组中切分的位置也能得到。为了使得时间复杂度最小,所以二分搜索两个数组中长度较小的那个数组。

关键的问题是如何切分数组 1 和数组 2 。其实就是如何切分数组 1 。先随便二分产生一个 midA,切分的线何时算满足了中位数的条件呢?即,线左边的数都小于右边的数,即,nums1[midA-1] ≤ nums2[midB] && nums2[midB-1] ≤ nums1[midA] 。如果这些条件都不满足,切分线就需要调整。如果 nums1[midA] < nums2[midB-1],说明 midA 这条线划分出来左边的数小了,切分线应该右移;如果 nums1[midA-1] > nums2[midB],说明 midA 这条线划分出来左边的数大了,切分线应该左移。经过多次调整以后,切分线总能找到满足条件的解。

假设现在找到了切分的两条线了,数组 1 在切分线两边的下标分别是 midA - 1 和 midA。数组 2 在切分线两边的下标分别是 midB - 1 和 midB。最终合并成最终数组,如果数组长度是奇数,那么中位数就是 max(nums1[midA-1], nums2[midB-1])。如果数组长度是偶数,那么中间位置的两个数依次是:max(nums1[midA-1], nums2[midB-1]) 和 min(nums1[midA], nums2[midB]),那么中位数就是 (max(nums1[midA-1], nums2[midB-1]) + min(nums1[midA], nums2[midB])) / 2。

class Solution{
    public double findMedianSortedArrays(int[] nums1, int[] nums2){
        if(nums1.length > nums2.length){
            return findMedianSortedArrays(nums2, nums1);
        }
        int low = 0, high = nums1.length;
        int k = (nums1.length + nums2.length + 1) >> 1;
        int midA = 0, midB = 0;
        while(low <= high){
            midA = (low + high) >> 1;
            midB = k - midA;
 			if(midA > 0 && nums1[midA - 1] > nums2[midB]){
                high = midA - 1;
            } else if(midA < nums1.length && nums1[midA] < nums2[midB - 1]){
                low = midA + 1;
            } else{
                break;
            }
        }
        int midLeft = 0, midRight = 0;
        if(midA == 0){
            midLeft = nums2[midB - 1];
        } else if(midB == 0){
            midLeft = nums1[midA - 1];
        } else{
            midLeft = Math.max(nums1[midA - 1], nums2[midB - 1]);
        }
        if(((nums1.length + nums2.length) & 1) == 1){
            return (double) midLeft;
        }
        if(midA == nums1.length){
            midRight = nums2[midB];
        } else if(midB == nums2.length){
            midRight = nums1[midA];
        } else{
            midRight = Math.min(nums1[midA], nums2[midB]);
        }
        return (double) (midLeft + midRight) / 2.0;
    }
}
func findMedianSortedArrays(nums1 []int, nums2 []int) float64 {
    if len(nums1) > len(nums2){
        return findMedianSortedArrays(nums2, nums1);
    }
    low, high, k, midA, midB := 0, len(nums1), (len(nums1) + len(nums2) + 1) >> 1, 0, 0
    for low <= high{
        midA = (low + high) >> 1
        midB = k - midA
        if midA > 0 && nums1[midA - 1] > nums2[midB]{
            high = midA - 1
        } else if midA < len(nums1) && nums1[midA] < nums2[midB - 1]{
            low = midA + 1
        } else{
            break
        }
    }
    midLeft, midRight := 0, 0
    if midA == 0{
        midLeft = nums2[midB - 1]
    } else if midB == 0{
        midLeft = nums1[midA - 1]
    } else{
        midLeft = max(nums1[midA - 1], nums2[midB - 1])
    }
    if (len(nums1) + len(nums2)) & 1 == 1{
        return float64(midLeft)
    }
    if midA == len(nums1){
        midRight = nums2[midB]
    } else if midB == len(nums2){
        midRight = nums1[midA]
    } else{
        midRight = min(nums1[midA], nums2[midB])
    }
    return float64(midLeft + midRight) / 2
}

func max(a, b int) int{
    if a > b{
        return a
    }
    return b
}

func min(a, b int) int{
    if a < b{
        return a
    }
    return b
}

3.盛最多水的容器

给你 n 个非负整数 a1,a2,…,an,每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0) 。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。

说明:你不能倾斜容器。

示例 1:

输入:[1,8,6,2,5,4,8,3,7]
输出:49

解释:图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。

示例 2:

输入:height = [1,1]
输出:1

示例 3:

输入:height = [4,3,2,1,4]
输出:16

示例 4:

输入:height = [1,2,1]
输出:2

提示:

n = height.length
2 <= n <= 3 * 104
0 <= height[i] <= 3 * 104

class Solution{
    public int maxArea(int[] height){
        int res = 0, start = 0, end = height.length - 1;
        while(start < end){
            int width = end - start;
            int high = 0;
            if(height[start] < height[end]){
                high = height[start++];
            } else{
                high = height[end--];
            }
            int area = high * width;
            res = Math.max(area, res);
        }
        return res;
    }
}
func maxArea(height []int) int{
    res, start, end := 0, 0, len(height) - 1
    for start < end{
        width := end - start
        high := 0
        if height[start] < height[end]{
            high = height[start]
            start++
        } else{
            high = height[end]
            end--
        }
        area := high * width
        if area > res{
            res = area
        }
    }
    return res
}

4. 存在重复元素

给定一个整数数组,判断是否存在重复元素。

如果存在一值在数组中出现至少两次,函数返回 true 。如果数组中每个元素都不相同,则返回 false 。

示例 1:

输入: [1,2,3,1]
输出: true

示例 2:

输入: [1,2,3,4]
输出: false

示例 3:

输入: [1,1,1,3,3,4,3,2,4,2]
输出: true

class Solution {
    public boolean containsDuplicate(int[] nums) {
		Set<Integer> set = new HashSet<>(nums.length);
        for(int n : nums){
            if(set.contains(n)){
                return true;
            }
            set.add(n);
        }
        return false;
    }
}
func containsDuplicate(nums []int) bool {
    m := make(map[int]bool, len(nums))
    for _, v := range(nums){
        if _, contain := m[v]; contain{
            return true
        }
        m[v] = true
    }
    return false
}

5. 反转字符串

编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 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 {
    public void reverseString(char[] s) {
        int mid = s.length / 2;
        for(int i = 0; i < mid; i++) {
            char c = s[i];
            s[i] = s[s.length - 1 - i];
            s[s.length - 1 - i] = c;
        }
    }
}
func reverseString(s []byte)  {
    mid := len(s) / 2
    for i := 0; i < mid; i++ {
        c := s[i]
        s[i] = s[len(s) - 1 - i]
        s[len(s) - 1 - i] = c
    }
}

6. 合并两个有序数组

给你两个有序整数数组 nums1 和 nums2,请你将 nums2 合并到 nums1 中,使 nums1 成为一个有序数组。

初始化 nums1 和 nums2 的元素数量分别为 m 和 n 。你可以假设 nums1 的空间大小等于 m + n,这样它就有足够的空间保存来自 nums2 的元素。

示例 1:

输入:nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3
输出:[1,2,2,3,5,6]

示例 2:

输入:nums1 = [1], m = 1, nums2 = [], n = 0
输出:[1]

提示:

  • nums1.length == m + n

  • nums2.length == n

  • 0 <= m, n <= 200

  • 1 <= m + n <= 200

  • -109 <= nums1[i], nums2[i] <= 109

class Solution {
    public void merge(int[] nums1, int m, int[] nums2, int n) {
        int i = m - 1, j = n - 1;
        for(int k = m + n - 1; k >= 0; k--) {
            int n1 = Integer.MIN_VALUE, n2 = Integer.MIN_VALUE;
            if(i >= 0) {
                n1 = nums1[i];
            }
            if(j >= 0) {
                n2 = nums2[j];
            }
            nums1[k] = n1 > n2 ? nums1[i--] : nums2[j--];
        }
    }
}
func merge(nums1 []int, m int, nums2 []int, n int)  {
    i, j, min := m-1, n-1, - 1 << 32
    for k := m+n-1; k >= 0; k-- {
        n1, n2 := min, min
        if i >= 0 {
            n1 = nums1[i]
        }
        if j >= 0 {
            n2 = nums2[j]
        }
        if n1 > n2 {
            nums1[k] = n1
            i--
        } else {
            nums1[k] = n2
            j--
        }
    }
}

7. 非递减数列

难度简单456

给你一个长度为 n 的整数数组,请你判断在 最多 改变 1 个元素的情况下,该数组能否变成一个非递减数列。

我们是这样定义一个非递减数列的: 对于数组中所有的 i (0 <= i <= n-2),总满足 nums[i] <= nums[i + 1]

示例 1:

输入: nums = [4,2,3]
输出: true
解释: 你可以通过把第一个4变成1来使得它成为一个非递减数列。

示例 2:

输入: nums = [4,2,1]
输出: false
解释: 你不能在只改变一个元素的情况下将其变为非递减数列。

说明:

  • 1 <= n <= 10 ^ 4
  • - 10 ^ 5 <= nums[i] <= 10 ^ 5
class Solution {
    public boolean checkPossibility(int[] nums) {
        int cnt = 0;
        for(int i = 0; i < nums.length - 1; i++) {
            int x = nums[i], y = nums[i+1];
            if(x > y) {
                if(++cnt > 1) {
                    return false;
                }
                if(i > 0 && nums[i-1] > y) {
                    nums[i+1] = x;
                }
            }
        }
        return true;
    }
}
func checkPossibility(nums []int) {
    cnt := 0
    for i := 0; i < len(nums) - 1; i++ {
        x, y := nums[i], nums[i+1]
        if x > y {
            cnt++
            if cnt > 1 {
                return false
            }
            if i > 0 && nums[i-1] > y {
                nums[i+1] = x
            }
        }
    }
    return true
}

8. 跳跃游戏 VI *

给你一个下标从 0 开始的整数数组 nums 和一个整数 k

一开始你在下标 0 处。每一步,你最多可以往前跳 k 步,但你不能跳出数组的边界。也就是说,你可以从下标 i 跳到 [i + 1, min(n - 1, i + k)] 包含 两个端点的任意位置。

你的目标是到达数组最后一个位置(下标为 n - 1 ),你的 得分 为经过的所有数字之和。

请你返回你能得到的 最大得分

示例 1:

输入:nums = [1,-1,-2,4,-7,3], k = 2
输出:7
解释:你可以选择子序列 [1,-1,4,3] (上面加粗的数字),和为 7 。

示例 2:

输入:nums = [10,-5,-2,4,0,3], k = 3
输出:17
解释:你可以选择子序列 [10,4,3] (上面加粗数字),和为 17 。

示例 3:

输入:nums = [1,-5,-20,4,-1,3,-6,-3], k = 2
输出:0

提示:

  • 1 <= nums.length, k <= 105
  • -104 <= nums[i] <= 104
class Solution {
    public int maxResult(int[] nums, int k) {
        int n = nums.length;
        int[] dp = new int[n];
        Deque<Integer> queue = new LinkedList<>();
        dp[0] = nums[0];
        queue.offerLast(0);
        for(int i = 1; i < n; i++) {
            if(i > k && i - k - 1 == queue.getFirst()) {
                queue.pollFirst();
            }
            dp[i] = nums[i] + dp[queue.getFirst()];
            while(!queue.isEmpty() && dp[queue.getLast()] < dp[i]) {
                queue.pollLast();
            }
        	queue.offerLast(i);
        }
    	return dp[n - 1];
    }
}
func maxResult(nums []int, k int) int {
    n := len(nums)
    dp := make([]int, n)
    queue := make([]int, 0)
    dp[0] = nums[0]
    queue = append(queue, 0)
    for i := 1; i < n; i++ {
        if i > k && i - k - 1 == queue[0] {
            queue = queue[1:]
        }
        dp[i] = nums[i] + dp[queue[0]]
        for len(queue) > 0 && dp[queue[len(queue) - 1]] < dp[i] {
            queue = queue[:len(queue) - 1]
        }
        queue = append(queue, i)
    }
    return dp[n - 1]
}

9. 移动零

给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。

示例:

输入: [0,1,0,3,12]
输出: [1,3,12,0,0]

说明:

必须在原数组上操作,不能拷贝额外的数组。
尽量减少操作次数。

class Solution {
    public void moveZeroes(int[] nums) {
        int j = 0;
        for(int i = 0; i < nums.length; i++) {
            if(nums[i] != 0) {
                if(i != j) {
                    int temp = nums[i];
                    nums[i] = nums[j];
                    nums[j] = temp;
                }
                j++;
            }
        }
    }
}
func moveZeroes(nums []int)  {
    j := 0
    for i := range nums {
        if nums[i] != 0 {
            if i != j {
                nums[i], nums[j] = nums[j], nums[i]
            }
            j++
        }
    }
}

10. 找到所有数组中消失的数字

难度简单600

给定一个范围在 1 ≤ a[i] ≤ n ( n = 数组大小 ) 的 整型数组,数组中的元素一些出现了两次,另一些只出现一次。

找到所有在 [1, n] 范围之间没有出现在数组中的数字。

您能在不使用额外空间且时间复杂度为*O(n)*的情况下完成这个任务吗? 你可以假定返回的数组不算在额外空间内。

示例:

输入:
[4,3,2,7,8,2,3,1]

输出:
[5,6]
class Solution {
    public List<Integer> findDisappearedNumbers(int[] nums) {
        int n = nums.length;
        for(int i = 0; i < n; i++) {
            int x = (nums[i] - 1) % n;
            nums[x] += n;
        }
        List<Integer> res = new ArrayList<>();
        for(int i = 0; i < n; i++) {
            if(nums[i] <= n) {
                res.add(i+1);
            }
        }
        return res;
    }
}
func findDisappearedNumbers(nums []int) []int {
    n := len(nums)
    for _, v := range nums {
        x := (v - 1) % n
        nums[x] += n
    }
    res := make([]int, 0)
    for i := 0; i < n; i++ {
        if nums[i] <= n {
            res = append(res, i+1)
        }
    }
    return res
}

11. 螺旋矩阵

给你一个 m 行 n 列的矩阵 matrix ,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素。

示例 1:

输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]
输出:[1,2,3,6,9,8,7,4,5]

示例 2:

输入:matrix = [[1,2,3,4],[5,6,7,8],[9,10,11,12]]
输出:[1,2,3,4,8,12,11,10,9,5,6,7]

提示:

  • m == matrix.length

  • n == matrix[i].length

  • 1 <= m, n <= 10

  • -100 <= matrix[i][j] <= 100

class Solution {
    public List<Integer> spiralOrder(int[][] matrix) {
		List<Integer> res = new ArrayList<>();
        int row = matrix.length;
        if(row == 0) {
            return res;
        }
        int col = matrix[0].length;
        int lr = 1, ud = 1, r = 0, c = 0;
        while(row > 0 && col > 0) {
            row--;
            for(int i = 0; i < col; i++) {
                res.add(matrix[r][c]);
                c += lr;
            }
            c -= lr;
            r += ud;
            lr *= -1;
            col--;
            for(int i = 0; i < row; i++) {
                res.add(matrix[r][c]);
                r += ud;
            }
            r -= ud;
            c += lr;
            ud *= -1;
        }
        return res;
    }
}
func spiralOrder(matrix [][]int) []int {
    res := make([]int, 0)
    row := len(matrix)
    if row == 0 {
        return res
    }
    col := len(matrix[0])
    lr, ud, r, c := 1, 1, 0, 0
    for row > 0 && col > 0 {
        row--
        for i := 0; i < col; i++ {
            res = append(res, matrix[r][c])
            c += lr
        }
        c -= lr
        r += ud
        lr *= -1
        col--
        for i := 0; i < row; i++ {
            res = append(res, matrix[r][c])
            r += ud
        }
        r -= ud
        c += lr
        ud *= -1
    }
    return res
}

12. 螺旋矩阵 II

给你一个正整数 n ,生成一个包含 1 到 n2 所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix 。

示例 1:

输入:n = 3
输出:[[1,2,3],[8,9,4],[7,6,5]]

示例 2:

输入:n = 1
输出:[[1]]

提示:

  • 1 <= n <= 20
class Solution {
    public int[][] generateMatrix(int n) {
		int[][] res = new int[n][n];
        int row = n, col = n, r = 0, c = 0;
        int lr = 1, ud = 1, element = 1;
        while(row > 0 && col > 0) {
            row--;
            for(int i = 0; i < col; i++) {
                res[r][c] = element++;
                c += lr;
            }
            c -= lr;
            r += ud;
            lr *= -1;
            col--;
            for(int i = 0; i < row; i++) {
                res[r][c] = element++;
                r += ud;
            }
            r -= ud;
            c += lr;
            ud *= -1;
        }
        return res;
    }
}
func generateMatrix(n int) [][]int {
    res := make([][]int, n)
    for i := 0; i < n; i++ {
        res[i] = make([]int, n)
    }
    row, col, r, c := n, n, 0, 0
    lr, ud, element := 1, 1, 1
    for row > 0 && col > 0 {
        row--
        for i := 0; i < col; i++ {
            res[r][c] = element
            element++
            c += lr
        }
        c -= lr
        r += ud
        lr *= -1
        col--
        for i := 0; i < row; i++ {
            res[r][c] = element
            element++
            r += ud
        }
        r -= ud
        c += lr
        ud *= -1
    }
    return res
}

13. 有效的数独

判断一个 9x9 的数独是否有效。只需要根据以下规则,验证已经填入的数字是否有效即可。

数字 1-9 在每一行只能出现一次。
数字 1-9 在每一列只能出现一次。
数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。

上图是一个部分填充的有效的数独。

数独部分空格内已填入了数字,空白格用 ‘.’ 表示。

示例 1:

输入:
[
[“5”,“3”,".",".",“7”,".",".",".","."],
[“6”,".",".",“1”,“9”,“5”,".",".","."],
[".",“9”,“8”,".",".",".",".",“6”,"."],
[“8”,".",".",".",“6”,".",".",".",“3”],
[“4”,".",".",“8”,".",“3”,".",".",“1”],
[“7”,".",".",".",“2”,".",".",".",“6”],
[".",“6”,".",".",".",".",“2”,“8”,"."],
[".",".",".",“4”,“1”,“9”,".",".",“5”],
[".",".",".",".",“8”,".",".",“7”,“9”]
]
输出: true

示例 2:

输入:
[
[“8”,“3”,".",".",“7”,".",".",".","."],
[“6”,".",".",“1”,“9”,“5”,".",".","."],
[".",“9”,“8”,".",".",".",".",“6”,"."],
[“8”,".",".",".",“6”,".",".",".",“3”],
[“4”,".",".",“8”,".",“3”,".",".",“1”],
[“7”,".",".",".",“2”,".",".",".",“6”],
[".",“6”,".",".",".",".",“2”,“8”,"."],
[".",".",".",“4”,“1”,“9”,".",".",“5”],
[".",".",".",".",“8”,".",".",“7”,“9”]
]
输出: false
解释: 除了第一行的第一个数字从 5 改为 8 以外,空格内其他数字均与 示例1 相同。
但由于位于左上角的 3x3 宫内有两个 8 存在, 因此这个数独是无效的。

说明:

  • 一个有效的数独(部分已被填充)不一定是可解的。

  • 只需要根据以上规则,验证已经填入的数字是否有效即可。

  • 给定数独序列只包含数字 1-9 和字符 ‘.’ 。

  • 给定数独永远是 9x9 形式的。

class Solution {
    public boolean isValidSudoku(char[][] board) {
        boolean[][] row = new boolean[9][9];
        boolean[][] col = new boolean[9][9];
        boolean[][] box = new boolean[9][9];
        for(int i = 0; i < 9; i++) {
            for(int j = 0; j < 9; j++) {
                if(board[i][j] == '.') {
                    continue;
                }
                int pos = board[i][j] - '1';
                if(row[i][pos]) return false;
                if(col[pos][j]) return false;
                if(box[j / 3 + i / 3 * 3][pos]) return false;
                
                row[i][pos] = true;
                col[pos][j] = true;
                box[j / 3 + i / 3 * 3][pos] = true;
            }
        }
        return true;
    }
}
func isValidSudoku(board [][]byte) bool {
    row := make([][]bool, 9)
    col := make([][]bool, 9)
    box := make([][]bool, 9)
    
    for i := 0; i < 9; i++ {
        row[i] = make([]bool, 9)
        col[i] = make([]bool, 9)
        box[i] = make([]bool, 9)
    }
    
    for i := 0; i < 9; i++ {
        for j := 0; j < 9; j++ {
            if board[i][j] == '.' {
                continue
            }
            pos := board[i][j] - '1'
            if row[i][pos] || col[pos][j] || box[j / 3 + i / 3 * 3][pos] {
                return false
            }
            
            row[i][pos] = true
            col[pos][j] = true
            box[j / 3 + i / 3 * 3][pos] = true
        }
    }
    return true
}

14. 除自身以外数组的乘积

给你一个长度为 n 的整数数组 nums,其中 n > 1,返回输出数组 output ,其中 output[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积。

示例:

输入: [1,2,3,4]
输出: [24,12,8,6]

提示:题目数据保证数组之中任意元素的全部前缀元素和后缀(甚至是整个数组)的乘积都在 32 位整数范围内。

说明: 请不要使用除法,且在 O(n) 时间复杂度内完成此题。

进阶:
你可以在常数空间复杂度内完成这个题目吗?( 出于对空间复杂度分析的目的,输出数组不被视为额外空间。)

class Solution {
    public int[] productExceptSelf(int[] nums) {
		int n = nums.length;
        int[] res = new int[n];
        res[0] = 1;
        for(int i = 1; i < n; i++) {
            res[i] = res[i-1] * nums[i-1];
        }
        int R = 1;
        for(int i = n-1; i >= 0; i--) {
            res[i] *= R;
            R *= nums[i];
        }
        return res;
    }
}
func productExceptSelf(nums []int) []int {
    n := len(nums)
    res := make([]int, n)
    res[0] = 1
    for i := 1; i < n; i++ {
        res[i] = res[i-1] * nums[i-1]
    }
    R := 1
    for i := n-1; i >= 0; i-- {
        res[i] *= R
        R *= nums[i]
    }
    return res
}

15. 数组的度

难度简单249

给定一个非空且只包含非负数的整数数组 nums,数组的度的定义是指数组里任一元素出现频数的最大值。

你的任务是在 nums 中找到与 nums 拥有相同大小的度的最短连续子数组,返回其长度。

示例 1:

输入:[1, 2, 2, 3, 1]
输出:2
解释:
输入数组的度是2,因为元素1和2的出现频数最大,均为2.
连续子数组里面拥有相同度的有如下所示:
[1, 2, 2, 3, 1], [1, 2, 2, 3], [2, 2, 3, 1], [1, 2, 2], [2, 2, 3], [2, 2]
最短连续子数组[2, 2]的长度为2,所以返回2.

示例 2:

输入:[1,2,2,3,1,4,2]
输出:6

提示:

  • nums.length 在1到 50,000 区间范围内。
  • nums[i] 是一个在 0 到 49,999 范围内的整数。
class Solution {
    public int findShortestSubArray(int[] nums) {
        int maxCount = 0, minWindow = 0;
        Map<Integer, int[]> map = new HashMap<>();
        for(int i = 0; i < nums.length; i++) {
            int[] pair = map.get(nums[i]);
            if(pair == null) {
                pair = new int[]{i, 1};
                map.put(nums[i], pair);
            } else {
                pair[1]++;
            }
            if(pair[1] > maxCount) {
                maxCount = pair[1];
                minWindow = i - pair[0] + 1;
            } else if(pair[1] == maxCount) {
                minWindow = Math.min(minWindow, i - pair[0] + 1);
            }
        }
        return minWindow;
    }
}
func findShortestSubArray(nums []int) int {
    maxCount, minWindow, len := 0, 0, len(nums)
    m := make(map[int][]int, 0)
    for i := 0; i < len; i++ {
        pair, ok := m[nums[i]]
        if !ok {
            pair = make([]int, 2)
            pair[0] = i
            pair[1] = 1
        } else {
            pair[1]++
        }
        m[nums[i]] = pair
        if pair[1] > maxCount {
            maxCount = pair[1]
            minWindow = i - pair[0] + 1
        } else if pair[1] == maxCount {
            minWindow = min(minWindow, i - pair[0] + 1)
        }
    }
    return minWindow
}

func min(n1, n2 int) int {
    if n1 < n2 {
        return n1
    }
    return n2
}

16. 最接近的三数之和

给定一个包括 n 个整数的数组 nums 和 一个目标值 target。找出 nums 中的三个整数,使得它们的和与 target 最接近。返回这三个数的和。假定每组输入只存在唯一答案。

示例:

输入:nums = [-1,2,1,-4], target = 1
输出:2
解释:与 target 最接近的和是 2 (-1 + 2 + 1 = 2) 。

提示:

  • 3 <= nums.length <= 10^3

  • -10^3 <= nums[i] <= 10^3

  • -10^4 <= target <= 10^4

class Solution {
    public int threeSumClosest(int[] nums, int target) {
		Arrays.sort(nums);
        int res = 0, diff = Integer.MAX_VALUE;
        for(int i = 0; i < nums.length - 2; i++) {
            for(int j = i+1, k = nums.length - 1; j < k;) {
                int sum = nums[i] + nums[j] + nums[k];
                if(Math.abs(sum - target) < diff) {
                    res = sum;
                    diff = Math.abs(sum - target);
                }
                if(sum == target) {
                    return sum;
                } else if(sum < target) {
                    j++;
                } else {
                    k--;
                }
            }
        }
        return res;
    }
}
func threeSumClosest(nums []int, target int) int {
    res, diff, n := 0, 1 << 32 - 1, len(nums)
    sort.Ints(nums)
    for i := 0; i < n-2; i++ {
        for j, k := i+1, n-1; j < k; {
            sum := nums[i] + nums[j] + nums[k]
            if abs(sum - target) < diff {
                res, diff = sum, abs(sum - target)
            }
            if sum == target {
                return sum
            } else if sum < target {
                j++
            } else {
                k--
            }
        }
    }
    return res
}

func abs(n int) int {
    if n < 0 {
        return -n
    }
    return n
}

17. 旋转图像

给定一个 n × n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。

你必须在 原地 旋转图像,这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。

示例 1:

输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]
输出:[[7,4,1],[8,5,2],[9,6,3]]

示例 2:

输入:matrix = [[5,1,9,11],[2,4,8,10],[13,3,6,7],[15,14,12,16]]
输出:[[15,13,2,5],[14,3,4,1],[12,6,8,9],[16,7,10,11]]

示例 3:

输入:matrix = [[1]]
输出:[[1]]

示例 4:

输入:matrix = [[1,2],[3,4]]
输出:[[3,1],[4,2]]

提示:

  • matrix.length == n

  • matrix[i].length == n

  • 1 <= n <= 20

  • -1000 <= matrix[i][j] <= 1000

class Solution {
   public void rotate(int[][] matrix) {
   	int n = matrix.length, mid = n >> 1;
       for(int i = 0; i < mid; i++) {
           for(int j = 0; j < n; j++) {
               swap(matrix, i, j, n-1-i, j);
           }
       }
       for(int i = 0; i < n; i++) {
           for(int j = i+1; j < n; j++) {
               swap(matrix, i, j, j, i);
           }
       }
   }
   
   private void swap(int[][] matrix, int i1, int j1, int i2, int j2) {
       int temp = matrix[i1][j1];
       matrix[i1][j1] = matrix[i2][j2];
       matrix[i2][j2] = temp;
   }
}
func rotate(matrix [][]int) {
    n := len(matrix)
    mid := n >> 1
    for i := 0; i < mid; i++ {
        ni := n - 1 - i
        for j := 0; j < n; j++ {
            matrix[i][j], matrix[ni][j] = matrix[ni][j], matrix[i][j]
        }
    }
    for i := 0; i < n; i++ {
        for j := i+1; j < n; j++ {
            matrix[i][j], matrix[j][i] = matrix[j][i], matrix[i][j]
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值