20200801.632(待).1692.64

**

一.

**美好的八月第一天,从碰到每日一题结束。
不会,复制粘贴交上去的。
要用堆,滑动窗口什么的。一点都不会,留着以后再说吧

只能剽窃我的儿子孙教授的解题思路

首先,我们想一下这样一个问题:题目要求是寻找最小区间,最小区间满足下面两点:

长度最小(首要)
长度相同时起点最小

长度最小的区间必然是需要我们在计算中找到的,但是起点最小的区间我们是可以知道的。就是从每个区间中找最小的元素,组成的新的区间,我们称其为起始区间。如果之后没有长度比起始区间长度更短的,那么起始区间就是我们所求的最小区间,因为起始区间的起点是最小的。

那么我们所需要做的就是搜索是否有比起始区间还要短的区间了。那么该如何搜索呢?
答案是每次都将当前区间中最小的元素丢弃,换成其原始数组中的下一个元素。就是说,如果当前我们从每个区间中选取的元素分别是a1_1,a2_1,a3_1…ak_1(前面的数字代表来自第几个数组,后面的数字表示该数是该数组的第几个元素),若此时最小的元素是ai_1,最大元素是aj_1,那么区间就为[ai_1, aj_1],区间中最小元素是ai_1,那么我们就将ai_1丢弃,将ai_2拿出来放进去。

原因:如果不换ai_1,那么区间的起点就一直是ai_1,而且区间长度不可能缩小,区间长度取决于起点和终点,而终点是不可能变小的。因为我们是从小到大进行元素的选取,我们每次丢弃一个元素,就要选择它在原数组中的下一位,而原数组是升序排列的。故终点不可能减小。
那么,我们只能够通过让起点增大来是区间缩小,即每次丢弃最小的元素,换成它原数组的下一个元素。然后再计算当前所选区间的长度,如果小于之前的区间长度就更新即可。

结束条件:当当前最小元素是其原来整数数组的最后一个元素时,就是结束的时候。因为之后的操作不可能更改起点了,只会让终点变大,即区间变长。

class Solution {
    class NumGroup{
        public NumGroup(int num, int grp){
            this.num = num;
            this.grp = grp;
        }
        int num; //数值
        int grp; //组号
    }
    public int[] smallestRange(List<List<Integer>> nums) {
        //因为每次都要找最小元素,所以维护一个最小堆比较合适
        PriorityQueue<NumGroup> numgrp = new PriorityQueue<>(new Comparator<NumGroup>(){
            @Override 
            public int compare(NumGroup n1, NumGroup n2){
                return n1.num - n2.num;
            }
        });

        int end = -100001;
        //记录每个数组当前的指针位置,一开始都指向第0个元素,即每个区间的最小元素
        int[] index = new int[nums.size()];

        //起始区间
        for(int i = 0; i < nums.size(); i++){
            if(nums.get(i).get(0) > end) end = nums.get(i).get(0);
            NumGroup num = new NumGroup(nums.get(i).get(0), i);
            numgrp.offer(num);
        }

        int max = end;
        int start = numgrp.peek().num;
        int min = start;
        int len = end - start + 1;

        while(true){
            //grp为当前最小元素的原数组号
            int grp = numgrp.poll().grp;
            //如果当前最小元素已经是原数组最大元素了,则退出
            if(index[grp]+1 == nums.get(grp).size()) break;

            //索引++
            index[grp]++;
            NumGroup n = new NumGroup(nums.get(grp).get(index[grp]), grp);
            numgrp.offer(n);
            //当前最大值
            if(n.num > max) max = n.num;
            min = numgrp.peek().num;
            //长度变小
            if(max-min+1 < len){
                start = min;
                end = max;
                len = max-min+1;
            }
        }

        return new int[]{start, end};
    }
}

作者:Girapath
链接:https://leetcode-cn.com/problems/smallest-range-covering-elements-from-k-lists/solution/tan-xin-duo-zhi-zhen-you-xian-ji-dui-lie-by-girapa/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

收获:
关于priorityqueue的应用,碰到了个问题
Cannot infer type arguments for PriorityQueue<>

用了网上的方法改了编译器的参数到5.0以上也没有好,等我以后再研究一下

二.

今天在知乎上看了leecode讲的动态规划,尝试着做了几个简单题。
1692.三步问题。
很简单的动态规划,小孩每次走1或2或3个台阶,问走n个可以有多少种方案。
动态规划首先要分析运用动态规划思想的正确性,
1.问题的优化街=解能否拆成子问题的优化解。
本题中,小孩走n步的优化解,可以由走了n-1再走1,走了n-2再走一次2,走了n-3,再走一次三得到。
**2.**要分析无后效性,n步的优化解fn只与f(n-1)和f(n-2),f(n-3)的值有关,与他们如何得来的无关,也就是说如何得到fn-1,n-2,n-3并不影响到fn。
证明正确性之后就可以构造递归方程了。

收获:
1.这道题思路还是比较清晰的,我这种菜狗都能写几遍就通过。
比较恶心的地方反而是题干中提到的解得数量可能会非常大,要mod1000000007.开始没注意这个,以为求完解得数量之后再mod就行,结果不行,后来发现是因为最终解如果很大,那么最终解前面的那几个子问题也不会小,也是会溢出的,所以这个就得每次求无论什么字问题的解,都得mod一下。

2要注意尽可能减少分支判断的数量和经过数量,我的大概44ms,别人的有的20多ms,我看了一下发现主要是他们想办法精简了if分支数量。
在这里插入图片描述64.最小路径和
一样的很简单地dp
官方的答案给的是要单独建立个存储子问题优化解的矩阵
但是由于每个节点只遍历一次,存储节点值的矩阵其实就可以用来存储dp(也就是到每个节点的最小值)
问题:我的第一次写的太粗糙了。没有考虑边界情况
题解这个写得就很巧妙,不是一次性的把gridij确定下来,而是先整个很大的整数min,先用min横着与grid比较,再竖着比较。就可以很简单地处理边界环境。但是略慢
在这里插入图片描述

在这里插入图片描述
下面是更快的,但是更占空间,我觉得也没快到哪去,这个本身用的时间就不是太多

class Solution {
    public int minPathSum(int[][] grid) {
        if(grid == null || grid.length == 0){
            return 0;
        }
        int rows = grid.length;
        int cols = grid[0].length;
        int[][] dp = new int[rows][cols];
        dp[0][0] = grid[0][0];
        for(int i = 1; i < rows; i++){
            dp[i][0] = dp[i-1][0] + grid[i][0];
        }
        for(int i = 1; i < cols; i++){
            dp[0][i] = dp[0][i-1] + grid[0][i];
        }
        for(int i = 1; i < rows; i++){
            for(int j = 1; j < cols; j++){
                dp[i][j] = Math.min(dp[i-1][j], dp[i][j-1])+grid[i][j];
            }
        }
        return dp[rows-1][cols-1];
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值