【每日一题】分割数组的最大值,矩阵最长递增路径,不同的二叉搜索树

由于刷题也比较多了,现在开始每周二总结一下上周的每日一题的比较不错的题目。并且由于打算转后端,会附上java的代码。

  • java 无sum函数
  • java 中先进先出队列的实现
  • Queue<int[]> queue = new LinkedList<int []>()
  • queue.offer(new int[] {x,y})
  • 判断是否空队列!queue.isEmpty()
  • len = queue.size()
  • java 中枚举 for (int [] dir:dis)
  • java 中树类问题的解决方法

1. 410分割数组的最大值(最大化最小值)

在这里插入图片描述

猛地一看思路并不十分明显,好像题目要求我们找到一种具体的分割方法,然后这种方法满足一种特性。其实并不是的。我们的实际要求是找到一个bar,这个bar是具有单调性的。这个子数组各自的和我们定义为target,最小值定义为bar。可以看出,当target >= bar的情况下时,我们是可以容易(贪心)找到一种分割让子数组的和都小于bar的。但是一但target<bar则无法。

因此我们实际上可以用二分的思路。在区间[max(nums, sum(nums)]之间寻找出来这个bar

# python
class Solution:
    def splitArray(self, nums: List[int], m: int) -> int:
        left, right = 0, sum(nums)
        while left<=right:
            mid = left+(right-left)//2
            if self.isvalid(nums, mid, m):
                right = mid-1
            else:
                left = mid+1
        return left

    def isvalid(self, nums, bar, m):
        cur = 0
        k = 1
        for i in nums:
            if cur+i<=bar:
                cur += i
            else:
                k += 1
                cur = i
                if cur>bar:
                    return False
        return k<=m

需要注意,java没有sum函数的,因此我们需要手动实现。

// java
class Solution {
    public int splitArray(int[] nums, int m) {
        int left = 0;
        int right = 0;
        for (int i = 0; i < nums.length; i++){
            right += nums[i];
            left = Math.max(left, nums[i]);
        }

        while (left<=right){
            int mid = left + (right - left)/2;
            if (check(nums, m, mid)){
                right = mid - 1;
            }
            else{
                left = mid + 1;
            }
            //System.out.println(mid);
        }
        return left;
    }    
    private boolean check(int[] nums, int m, int bar){
        int cur = 0;
        for (int i = 0; i<nums.length; i++){
            if (cur + nums[i] > bar){
                m -= 1;
                cur = nums[i];
            }
            else{
                cur += nums[i];
            }
        }
        return m-1 >= 0;
    } 
    
}

2. 329矩阵最长递增路径

在这里插入图片描述

基本思路是类似DP思路的一种BFS,但是需要提前处理好每个位置的入度。首先我们需要遍历一边数组,保存每个位置附近比自己大的数字的个数,也就是出度。这样如果出度为0,表示自己是周围最大的,可以作为起点,将该点压入队列。

然后,进行每次整体弹出的bfs,每次将队头点四周的点的出度减一,表示已经可以到达,当某周围节点的出度变为0时,表示该点周围大于它的点都被遍历了,可以入队了。最终返回整体出队的次数。

class Solution:
    def longestIncreasingPath(self, matrix: List[List[int]]) -> int:
        if not matrix:
            return 0
        n = len(matrix)
        m = len(matrix[0])
        
        queue = collections.deque()
        ans = 0
        outdegree = [[0]*(m) for _ in range(n)]
        dis = [[0,1], [1,0],[0,-1], [-1,0]]
        for i in range(n):
            for j in range(m):
                for mx, my in dis:
                    cx,cy = mx+i,my+j
                    if 0<=cx<n and 0<=cy<m and matrix[cx][cy]>matrix[i][j]:
                        outdegree[i][j] += 1
                if outdegree[i][j] == 0:
                    queue.append((i,j))

        while queue:
            n1 = len(queue)
            ans += 1
            for i in range(n1):
                x,y = queue.popleft()
                for mx, my in dis:
                    cx, cy = x+mx, y+my
                    if 0<=cx<n and 0<=cy<m and matrix[cx][cy]<matrix[x][y]:
                        outdegree[cx][cy] -= 1
                        if outdegree[cx][cy] == 0:
                            queue.append((cx,cy))
        return ans
class Solution {
    public int longestIncreasingPath(int[][] matrix) {
        if (matrix == null || matrix.length == 0 ||matrix[0].length == 0) return 0;
        int n = matrix.length;
        int m = matrix[0].length;
        int[][] grid = new int[n][m];
        int [][] dis = {{0,1}, {1,0}, {0,-1}, {-1,0}};

        Queue<int[]> queue = new LinkedList<int[]>();

        for (int i = 0; i < n; i++){
            for (int j = 0; j<m; j++){
                for (int [] dir:dis){
                    int mx = i+dir[0], my = j + dir[1];
                    if (0<=mx && n>mx && 0<=my && m>my&&matrix[mx][my]>matrix[i][j]){
                        grid[i][j]++;
                    }

                }
                if (grid[i][j] == 0) queue.offer(new int[] {i,j}); // 最大值
            }
        }
        int ans = 0;
        while (!queue.isEmpty()){
            int len = queue.size();
            ans ++;
            for (int i = 0; i< len; i++){
                int[] cell = queue.poll();
                int cx = cell[0], cy = cell[1];
                for (int[] dir:dis){
                    int mx = cx+dir[0], my = cy+dir[1];
                    if (0<=mx && n>mx && 0<=my && m>my && matrix[mx][my]<matrix[cx][cy]){
                        grid[mx][my]--;
                        if (grid[mx][my] == 0) queue.offer(new int[] {mx,my});
                    }
                }
            }
        }
        return ans;
    }
}

3. 95不同的二叉搜索树

在这里插入图片描述

一道挺有意思的题目,要求生成不一样的二叉搜索树。其实考察的还是递归的思路,我们每次只考虑根节点为root = cur,因此左侧可能的二叉树就是[star, cur-1]这个区间内的二叉搜索树,右侧就是[cur+1, end]这个区间里的二叉搜索树。最后进行组合即可。

class Solution:
    def generateTrees(self, n: int) -> List[TreeNode]:
        if n == 0:
            return []
        return self.helper(1, n)
    
    def helper(self, star, end):

        if end < star:
            return [None]  # 需要注意这里的边界条件,此时返回None对应的就是不存在,而不是返回空数组
        ans = []
        for i in range(star, end+1):
            left = self.helper(star, i-1)
            right = self.helper(i+1, end)
            for item_l in left:
                for item_r in right:
                    cur = TreeNode(i)
                    cur.left = item_l
                    cur.right = item_r
                    ans.append(cur)
        return ans
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public List<TreeNode> generateTrees(int n) {
        if (n == 0) return new LinkedList<TreeNode>();
        return helper(1, n);
    }

    private List<TreeNode> helper(int star, int end){
        List<TreeNode> all = new LinkedList<TreeNode>();
        if (end<star){
            all.add(null);
            return all;
        }
        for (int i = star; i <= end; i++){
            List<TreeNode> lefts = helper(star, i-1);
            List<TreeNode> rights = helper(i+1, end);
            for (TreeNode left:lefts){
                for (TreeNode right:rights){
                    TreeNode cur = new TreeNode(i);
                    cur.left = left;
                    cur.right = right;
                    all.add(cur);
                }
            }
        }
        return all;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值