3/19

739 每日温度

思路1: 暴力
针对每一个温度,找下一个比自己大的温度

class Solution {
    public int[] dailyTemperatures(int[] T) {
        for(int i=0;i<T.length;i++){
            boolean flag=false;
            for(int j=i+1;j<T.length;j++){
                if(T[j]>T[I]){
                    T[i]=j-i;
                    flag=true;
                    break;
                }
            }
            if(!flag){
                T[i]=0;
            }
        }
        return T;
    }
}

思路2:
如何在思路1的基础上优化改进?怎样减少遍历次数呢?
我们可以分析,遍历一次数组中所有的值应该是少不了的,因为至少数组中每个值都需要计算一遍,所以时间复杂度肯定大于 O(n)。关键是要减少为每个数寻找值遍历次数。



如图所示,绿色部分区域会给多次遍历,如果我们能减少这部分区域的遍历次数,就能整体提高运算效率。
(在75找到76的过程中,已经遍历过71~72了)
如果我们先从右边计算,那么我们计算过的位置就不需要重复计算,如图所示:



关键在于“跳”的思想,可以往后跳跃

比如当前我们需要计算 75 位置,先向右遍历到 71(先看看自己右边的,所以j的初值是i+1 即j=i+1),因为我们已经计算好了 71 位置对应的值为 2,那么我们就可以直接 跳 2 位 再进行比较,利用了已经有的结果,减少了遍历的次数。

该思路的代码也不好写,自己写了挺久,代码也不好
第二个for的结束循环条件自己写的很奇怪,应该是j < length,表明不能再跳了,到头了,虽然实际上并不可能越界,因为最后一个是0
别人写的

public int[] dailyTemperatures(int[] T) {
    int length = T.length;
    int[] result = new int[length];

    //从右向左遍历
    for (int i = length - 2; i >= 0; i--) {
        // j+= result[j]是利用已经有的结果进行跳跃
        for (int j = i + 1; j < length; j+= result[j]) {
            if (T[j] > T[i]) {
                result[i] = j - I;
                break;//退出当前循环
            } else if (result[j] == 0) { //遇到0表示后面不会有更大的值,那当然当前值就应该也为0
                result[i] = 0;
                break;//退出当前循环
            }
        }
    }

    return result;
}

思路3:栈
没实现没理解

//找出数组中大于当前元素的第一个元素,到当前元素的距离
//递减栈,当前元素与栈中元素比较,小则入栈,大则出栈并将二者之间的下标差值为出栈元素的结果值,并继续比较下一个栈顶元素
//如果栈为空,直接入栈(表示前面元素都找到了比自己大的值)

 class Solution {
    public int[] dailyTemperatures(int[] T) {
        Stack<Integer> stack = new Stack<>();
        int[] res = new int[T.length];
        for(int i = 0; i < T.length; ++i){
            while(!stack.isEmpty() && T[i] > T[stack.peek()]){
                int temp = stack.pop();
                res[temp] = i - temp;
            }
            stack.push(i);
        }
        return res;
    }
}

维护递减栈,后入栈的元素总比栈顶元素小。

比对当前元素与栈顶元素的大小
若当前元素 < 栈顶元素:入栈
若当前元素 > 栈顶元素:弹出栈顶元素,记录两者下标差值即为所求天数
这里用栈记录的是 T 的下标。

class Solution(object):
    def dailyTemperatures(self, T):
        """
        :type T: List[int]
        :rtype: List[int]
        """
        stack = list()
        t_length = len(T)
        res_list = [0 for _ in range(t_length)]
        
        for key, value in enumerate(T):     
            if stack:
                while stack and T[stack[-1]] < value:
                    res_list[stack[-1]] = key - stack[-1]
                    stack.pop()
            stack.append(key)
        return res_list

这个的方法2
https://leetcode-cn.com/problems/daily-temperatures/solution/mei-ri-wen-du-by-leetcode-solution/

https://leetcode-cn.com/problems/daily-temperatures/solution/leetcode-tu-jie-739mei-ri-wen-du-by-misterbooo/

思路4:
时间紧急没看方法1
https://leetcode-cn.com/problems/daily-temperatures/solution/mei-ri-wen-du-by-leetcode-solution/

647 回文子串

思路1:运用之前做过的最长回文子串的思路完成
20% 30%
dp[i][j]表明s[i~j]是否回文
if s[i]==s[j]
dp[i][j]=dp[i+1][j-1]
else
dp[i][j]=0;

一个个判断过去,如果是,则计数加一

class Solution {
    public int countSubstrings(String s) {
        int len=s.length();
        boolean[][] dp=new boolean[len][len];
        int cnt=0;
        for(int i=0;i<len;i++){
            dp[i][i]=true;
            cnt++;
            if(i<len-1&&s.charAt(i)==s.charAt(i+1)){
                dp[i][i+1]=true;
                cnt++;
            }
        }
        for(int l=3;l<=len;l++){
            for(int i=0;i+l-1<len;i++){
                if(s.charAt(i)==s.charAt(i+l-1)){
                    dp[i][i+l-1]=dp[i+1][i+l-2];
                    if(dp[i][i+l-1]==true) cnt++;
                }

              //if(s.charAt(i)==s.charAt(i+l-1) && dp[i+1][i+l-2]){
                    //dp[i][i+l-1]=true;
                    //cnt++;
                //} 这样写也可以
                else dp[i][i+l-1]=false;
            }
        }
        return cnt;
    }
}

动态规划其他人的写法:
没看明白

class Solution {
    public int countSubstrings(String s) {
        int res = 0;
        int n = s.length();
        
        // dp[i][j] 表示[i,j]的字符是否为回文子串
        boolean[][] dp = new boolean[n][n];
        
        // 注意,外层循环要倒着写,内层循环要正着写
        // 因为要求dp[i][j] 需要知道dp[i+1][j-1]
        for(int i=n-1; i>=0; i--){ 
            for(int j=i; j<n; j++){
                
                // (s.charAt(i)==s.charAt(j) 时,当元素个数为1,2,3个时,一定为回文子串
                if(s.charAt(i)==s.charAt(j) && (j-i<=2 || dp[i+1][j-1])){
                    dp[i][j] = true;
                    res++;
                }
            }
        }
        
       return res; 
    }
}

dp降维优化
没看明白

class Solution {
    public int countSubstrings(String s) {

        // dp[i][j]:s[i : j] 是否为回文子串
        // 转移方程:dp[i][j] = s[i] == s[j] && dp[i + 1][j - 1]
         // 计算顺序:i 从大到小,j 任意
        
        // i 那维可以消掉,计算顺序:i 从大到小,j 从大到小

        int res = 0;
        boolean[] dp = new boolean[s.length()];

        for (int i = s.length() - 1; i >= 0; i--) {
            for (int j = s.length() - 1; j >= i; j--) {
                // aa a  aaa 肯定是回文
                dp[j] = s.charAt(i) == s.charAt(j) && (j - i <= 2 || dp[j - 1]);
                if (dp[j]) {
                    res++;
                }
            }
        }
        return res;
    }
}

这里说了为什么要降 怎么想到降维
https://leetcode-cn.com/problems/palindromic-substrings/solution/shou-hua-tu-jie-dong-tai-gui-hua-si-lu-by-hyj8/

思路2:中心扩展法
没看明白
感觉和dp思路差不多
https://leetcode-cn.com/problems/palindromic-substrings/solution/liang-dao-hui-wen-zi-chuan-de-jie-fa-xiang-jie-zho/

该思路的评论区:

  • left和center ,是如何看出存在2倍关系的?
  • 想问一下动态规划中:
    for (int j = 0; j < s.length(); j++) {
    for (int i = 0; i <= j; i++)
    这个循环是怎么想的,为什么先限定j 而不是

for(int i= 0; i < s.length(), i++){
for(int j = i; j <s.length(), j++){

198 打家劫舍

思路1:超时
dfs遍历所有方案,找出最大的

class Solution {
    public int rob(int[] nums) {
        int max=0,cnt=0;
        return dfs(nums,cnt,max,0);
    }

    int dfs(int[] nums,int cnt,int max,int index){
        if(index>=nums.length){
            if(cnt>max){
                max=cnt;
            }
            return max;
        }
        return Math.max(dfs(nums,cnt+nums[index],max,index+2),
        dfs(nums,cnt,max,index+1));
    }
}

思路2:动态规划
!!动态规划的的四个解题步骤是:

  • 定义子问题
  • 写出子问题的递推关系
  • 确定 DP 数组的计算顺序
  • 空间优化(可选)

下面我们一步一步地进行讲解。

步骤一:定义子问题
稍微接触过一点动态规划的朋友都知道动态规划有一个“子问题”的定义。什么是子问题?子问题是和原问题相似,但规模较小的问题。例如这道小偷问题,原问题是“从全部房子中能偷到的最大金额”,将问题的规模缩小,子问题就是“从 k 个房子中能偷到的最大金额”,用 f(k) 表示。
(重点:“从 k 个房子中能偷到的最大金额”,你不用管第k间房子偷不偷,f(k)的定义就是:“从 k 个房子中能偷到的最大金额”。第k间不一定偷)


可以看到,子问题是参数化的,我们定义的子问题中有参数 k。假设一共有 n 个房子的话,就一共有 n 个子问题。动态规划实际上就是通过求这一堆子问题的解,来求出原问题的解。这要求子问题需要具备两个性质:

  • 原问题要能由子问题表示。
    例如这道小偷问题中,k=n 时实际上就是原问题。否则,解了半天子问题还是解不出原问题,那子问题岂不是白解了。
  • 一个子问题的解要能通过其他子问题的解求出。
    例如这道小偷问题中,f(k) 可以由 f(k−1) 和 f(k−2) 求出,具体原理后面会解释。这个性质就是教科书中所说的“最优子结构”。如果定义不出这样的子问题,那么这道题实际上没法用动态规划解。
    小偷问题由于比较简单,定义子问题实际上是很直观的。一些比较难的动态规划题目可能需要一些定义子问题的技巧。

具体看这里:https://leetcode-cn.com/problems/house-robber/solution/dong-tai-gui-hua-jie-ti-si-bu-zou-xiang-jie-cjavap/

class Solution {
    public int rob(int[] nums) {
        int[] dp=new int[nums.length+1];//!!!!!
        dp[0]=0;dp[1]=nums[0];
        for(int i=2;i<=nums.length;i++){
            dp[i]=Math.max(dp[i-1],dp[i-2]+nums[i-1]);
        }
        return dp[nums.length];
    }
}

终结解惑!
https://leetcode-cn.com/problems/house-robber/solution/da-jia-jie-she-dong-tai-gui-hua-jie-gou-hua-si-lu-/

207 课程表

题意:你这个学期必须选修 numCourses 门课程,所以只要课程间形成了环,你就无法选修完所有的课程
思路:拓扑排序(广度优先遍历)
算法笔记415
关键点:邻接表、入度数组、队列、java容器的使用
代码艰难的按照思路写出来

class Solution {
    public boolean canFinish(int numCourses, int[][] prerequisites) {
        int[] inDegree=new int[numCourses];
        List<List<Integer>> adjacency=new ArrayList<>();//邻接表
        LinkedList<Integer> queue=new LinkedList<>();
        //Queue<Integer> queue = new LinkedList<>();
        for(int i=0;i<numCourses;i++){//重要
            adjacency.add(new ArrayList<>());
        }
        for(int i=0;i<prerequisites.length;i++){
            int pre=prerequisites[i][0],next=prerequisites[i][1];
            inDegree[next]++;
            adjacency.get(pre).add(next);//!!
        }
        for(int i=0;i<numCourses;i++){
            if(inDegree[i]==0) queue.offer(i);
        }
        int cnt=0;
        while(queue.size()>0){
        //while(!queue.isEmpty()) {
            int cur=queue.poll();cnt++;
            //删除所有以它为出度的
            //for(int j=0;j<adjacency.get(cur).size();j++){
            for(int next:adjacency.get(cur)){
                //int next=adjacency.get(cur).get(j);
                //inDegree[next]--;
                //if(inDegree[next]==0) queue.offer(next);
                if(--inDegree[next]==0) queue.offer(next);//!
            }
        }
        if(cnt==numCourses) return true;
        else return false;
    }
}

标准代码

class Solution {
    public boolean canFinish(int numCourses, int[][] prerequisites) {
        int[] indegrees = new int[numCourses];
        List<List<Integer>> adjacency = new ArrayList<>();
        Queue<Integer> queue = new LinkedList<>();
        for(int i = 0; i < numCourses; i++)
            adjacency.add(new ArrayList<>());
        // Get the indegree and adjacency of every course.
        for(int[] cp : prerequisites) {
            indegrees[cp[0]]++;
            adjacency.get(cp[1]).add(cp[0]);
        }
        // Get all the courses with the indegree of 0.
        for(int i = 0; i < numCourses; i++)
            if(indegrees[i] == 0) queue.add(i);
        // BFS TopSort.
        while(!queue.isEmpty()) {
            int pre = queue.poll();
            numCourses--;
            for(int cur : adjacency.get(pre))
                if(--indegrees[cur] == 0) queue.add(cur);
        }
        return numCourses == 0;
    }
}

思路2:深度优先遍历
没看 自己找题解或者评论区吧

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,036评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,046评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,411评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,622评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,661评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,521评论 1 304
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,288评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,200评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,644评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,837评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,953评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,673评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,281评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,889评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,011评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,119评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,901评论 2 355

推荐阅读更多精彩内容