LeetCode 1185. 一周中的第几天 / 913. 猫和老鼠(博弈,动态规划) / 1576. 替换所有的问号

1185. 一周中的第几天

2021.1.3 每日一题

题目描述

给你一个日期,请你设计一个算法来判断它是对应一周中的哪一天。

输入为三个整数:day、month 和 year,分别表示日、月、年。

您返回的结果必须是这几个值中的一个 {“Sunday”, “Monday”, “Tuesday”, “Wednesday”, “Thursday”, “Friday”, “Saturday”}。

示例 1:

输入:day = 31, month = 8, year = 2019
输出:“Saturday”

示例 2:

输入:day = 18, month = 7, year = 1999
输出:“Sunday”

示例 3:

输入:day = 15, month = 8, year = 1993
输出:“Sunday”

提示:

给出的日期一定是在 1971 到 2100 年之间的有效日期。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/day-of-the-week
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

先输入个例子,看1971年1月1日是星期几,然后再根据这个基数计算其他天数是星期几

class Solution {
    static String[] week = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
    static int[] monthday = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    public String dayOfTheWeek(int day, int month, int year) {
        //肯定得有个基数开始算,例如知道1971年1月1日是星期几
        //看了题解,是星期五,那么计算当前日期与该日期的天数差就可以了
        //和那天计算多少天一样

        //先计算年份
        int temp = 365 * (year - 1971);
        //加上闰年的个数,例如1972年,就加1
        //因为最多是2100年,所以没有判断世纪闰年
        temp += (year - 1969) / 4;

        //计算月份
        for(int i = 0; i < month - 1; i++){
            temp += monthday[i];
        }
        //判断当前年份是否是闰年
        if((year % 400 == 0 || (year % 4 == 0 && year % 100 != 0)) && month > 2)
            temp++;
        
        temp += day;
        //System.out.println(temp);
        int idx = (temp % 7 + 4) % 7;
        return week[idx];
    }
}

913. 猫和老鼠

2021.1.4 每日一题

题目描述

两位玩家分别扮演猫和老鼠,在一张 无向 图上进行游戏,两人轮流行动。

图的形式是:graph[a] 是一个列表,由满足 ab 是图中的一条边的所有节点 b 组成。

老鼠从节点 1 开始,第一个出发;猫从节点 2 开始,第二个出发。在节点 0 处有一个洞。

在每个玩家的行动中,他们 必须 沿着图中与所在当前位置连通的一条边移动。例如,如果老鼠在节点 1 ,那么它必须移动到 graph[1] 中的任一节点。

此外,猫无法移动到洞中(节点 0)。

然后,游戏在出现以下三种情形之一时结束:

如果猫和老鼠出现在同一个节点,猫获胜。
如果老鼠到达洞中,老鼠获胜。
如果某一位置重复出现(即,玩家的位置和移动顺序都与上一次行动相同),游戏平局。
给你一张图 graph ,并假设两位玩家都都以最佳状态参与游戏:

如果老鼠获胜,则返回 1;
如果猫获胜,则返回 2;
如果平局,则返回 0 。

示例 1:

LeetCode 1185. 一周中的第几天 / 913. 猫和老鼠(博弈,动态规划) / 1576. 替换所有的问号
输入:graph = [[2,5],[3],[0,4,5],[1,4,5],[2,3],[0,2,3]]
输出:0

示例 2:

LeetCode 1185. 一周中的第几天 / 913. 猫和老鼠(博弈,动态规划) / 1576. 替换所有的问号
输入:graph = [[1,3],[0],[3],[0,2]]
输出:1

提示:

3 <= graph.length <= 50
1 <= graph[i].length < graph.length
0 <= graph[i][j] < graph.length
graph[i][j] != i
graph[i] 互不相同
猫和老鼠在游戏中总是移动

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/cat-and-mouse
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

按照下面思路写的代码,然后倒在了[[2,3],[3,4],[0,4],[0,1],[1,2]]这个例子上
这个例子中,按照我的代码,老鼠有可能被抓住,也有可能进洞,所以结果就是平局,但是实际上老鼠肯定比猫先进洞,所以是1
但是这个情况怎么考虑呢,考虑与0的距离吗,也不太行啊

class Solution {
    int[][] used;
    int[][] graph;
    public int catMouseGame(int[][] graph) {
        //老鼠肯定想往洞靠近,但是不能走猫的路线,但是怎么保证是走的最优路线呢
        //而猫呢,是想抓老鼠,但是如果都走一步的情况下,除非是死胡同,猫才能获胜,否则最多平局
        //可以用递归的方式进行模拟,如果说猫怎么走都能抓住老鼠,或者老鼠怎么走都能进洞是两种特殊情况
        //否则都是平局
        //另外,如果2不能走到1,那么就是老鼠赢,如果老鼠比猫离的0近,那么老鼠赢
        //如果猫怎么走,老鼠都能进洞,那么就是老鼠赢,如果老鼠怎么走,都要被抓住就是猫赢
        //其他情况就是平局

        //先写个深度优先看看
        this.graph = graph;
        int l = graph.length;
        used = new int[l][l];
        for(int[] t : used){
            Arrays.fill(t, -1);
        }
        return helper(2, 1);
    }

    //猫的位置和鼠的位置,上一步猫和老鼠的位置
    public int helper(int posc, int posm){
        //如果此时鼠的位置在0,那么老鼠获胜
        if(posm == 0)
            return 1;
        //如果此时鼠的位置只能走到猫的位置,那么猫获胜
        if(graph[posm].length == 1 && graph[posm][0] == posc)
            return 2;
        
        int[] tempm = graph[posm];
        int[] tempc = graph[posc];
        
        boolean catwin = false;
        boolean mousewin = false;
        //遍历所有老鼠下一步的位置,如果所有老鼠的位置都返回1,那么才是1
        //如果都返回2,那么才是2,如果有1有2,那么就是0
        
        //表示当前位置正在遍历
        used[posm][posc] = 3;
        for(int nextm : tempm){
            //如果老鼠的下一个位置是0,那么就返回1
            if(nextm == 0)  {
                mousewin = true;
                break;
            }
            //遍历所有猫的位置    
            for(int nextc : tempc){
                //如果猫到了0位置,说明此路不通
                if(nextc == 0)
                    continue;
                //如果猫走到了老鼠的位置,说明肯定能抓到
                if(nextc == nextm){
                    catwin = true;
                    continue;
                }
                if(used[nextm][nextc] != -1){
                    //如果当前位置正在被遍历,那么就跳过这个位置
                    if(used[nextm][nextc] == 3){
                        continue;
                    }
                    else if(used[nextm][nextc] == 1){
                        mousewin = true;
                    }
                    else if(used[posm][posc] == 2){
                        catwin = true;
                    }else{
                        used[posm][posc] = 0;
                        return 0;
                    }
                }
                    
                int t = helper(nextc, nextm);
                //如果老鼠能赢
                if(t == 1)
                    mousewin = true;
                //如果猫能赢
                if(t == 2)
                    catwin = true;
            }
        }
        if(catwin && !mousewin)
            used[posm][posc] = 2;
        else if(mousewin && !catwin)
            used[posm][posc] = 1;
        else 
            used[posm][posc] = 0;
        return used[posm][posc];
    }
}

看了题解,竟然需要再加上一个轮次的维度才能表示正确结果
对于老鼠来说,如果能走到0,其实就赢了,因为默认猫采取的也是最优策略
同理,对于猫来说,抓住老鼠,也就赢了

class Solution {
    int[][][] used;
    int[][] graph;
    int l;
    public int catMouseGame(int[][] graph) {
        //老鼠肯定想往洞靠近,但是不能走猫的路线,但是怎么保证是走的最优路线呢
        //而猫呢,是想抓老鼠,但是如果都走一步的情况下,除非是死胡同,猫才能获胜,否则最多平局
        //可以用递归的方式进行模拟,如果说猫怎么走都能抓住老鼠,或者老鼠怎么走都能进洞是两种特殊情况
        //否则都是平局
        //另外,如果2不能走到1,那么就是老鼠赢,如果老鼠比猫离的0近,那么老鼠赢
        //如果猫怎么走,老鼠都能进洞,那么就是老鼠赢,如果老鼠怎么走,都要被抓住就是猫赢
        //其他情况就是平局

        //先写个深度优先看看
        this.graph = graph;
        l = graph.length;
        used = new int[l][l][2 * l];
        for(int[][] t : used){
            for(int[] tt : t){
                Arrays.fill(tt, -1);
            }
        }
        return helper(2, 1, 0);
    }

    //猫的位置和鼠的位置,当前轮次
    //返回值表示当前轮次,猫和老鼠在当前位置最后的胜利者
    public int helper(int posc, int posm, int k){
        //如果走过一轮了,还没有分出胜负,那么返回0
        if(k >= 2 * l)
            return 0;
        //如果此时鼠的位置在0,那么老鼠获胜
        if(posm == 0)
            return used[posm][posc][k] = 1;
        //如果猫在老鼠的位置,那么猫获胜
        if(posc == posm)
            return used[posm][posc][k] = 2;
        if(used[posm][posc][k] != -1)
            return used[posm][posc][k];
        
        int[] tempm = graph[posm];
        int[] tempc = graph[posc];
        
        //当前正在老鼠的回合,对于老鼠来说,如果能走到0,那么就赢了,因为猫使用的也是最优策略
        if(k % 2 == 0){
            int res = 2;
            for(int next : tempm){
                int ans = helper(posc, next, k + 1);
                //如果老鼠能赢的话,那么就返回老鼠赢
                if(ans == 1)    
                    return used[posm][posc][k] = 1;
                if(ans == 0)
                    res = 0;
            }
            return used[posm][posc][k] = res;
        //当前猫的回合,对于猫来说,如果抓住老鼠,那么就赢了,因为老鼠也使用的是最优策略
        }else{
            int res = 1;
            for(int next : tempc){
                if(next == 0)
                    continue;
                int ans = helper(next, posm, k + 1);
                if(ans == 2)
                    return used[posm][posc][k] = 2;
                if(ans == 0)
                    res = 0;
            }
            return used[posm][posc][k] = res;
        }
    }
}

再次看博弈这道题,就是分两个人的动作,也就是分两个人考虑,按照轮次来依次进行操作,如果轮次超过了2k,说明在最优策略下,两个人已经走过了一轮,所以就是平局
而我想的并没有考虑轮次的情况,而是直接判断如何获胜或者失败,相当于不是在博弈
还有看到的另一种解法是极大极小的做法,其实和这个道理上是一样的,只不过这种做法是将两个人的视角变成一个人的视角了

1576. 替换所有的问号

2021.1.5 每日一题

题目描述

给你一个仅包含小写英文字母和 ‘?’ 字符的字符串 s,请你将所有的 ‘?’ 转换为若干小写字母,使最终的字符串不包含任何 连续重复 的字符。

注意:你 不能 修改非 ‘?’ 字符。

题目测试用例保证 除 ‘?’ 字符 之外,不存在连续重复的字符。

在完成所有转换(可能无需转换)后返回最终的字符串。如果有多个解决方案,请返回其中任何一个。可以证明,在给定的约束条件下,答案总是存在的。

示例 1:

输入:s = “?zs”
输出:“azs”
解释:该示例共有 25 种解决方案,从 “azs” 到 “yzs” 都是符合题目要求的。只有 “z” 是无效的修改,因为字符串 “zzs” 中有连续重复的两个 ‘z’ 。

示例 2:

输入:s = “ubv?w”
输出:“ubvaw”
解释:该示例共有 24 种解决方案,只有替换成 “v” 和 “w” 不符合题目要求。因为 “ubvvw” 和 “ubvww” 都包含连续重复的字符。

示例 3:

输入:s = “j?qg??b”
输出:“jaqgacb”

示例 4:

输入:s = “??yw?ipkj?”
输出:“acywaipkja”

提示:

1 <= s.length <= 100
s 仅包含小写英文字母和 ‘?’ 字符

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/replace-all-s-to-avoid-consecutive-repeating-characters
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

判断是不是ab就行了,其他不用看,不过去看看题解还有什么更好的方法
好像都跟我的差不多哎,只不过是把判断三个字母写成循环的形式了

class Solution {
    public String modifyString(String s) {
        //其实就判断三个字符有没有就行了
        int l = s.length();
        char[] cc = s.toCharArray();
        for(int i = 0; i < l; i++){
            char c = cc[i];
            if(c != '?')
                continue;
            boolean isa = false, isb = false;
            char last = i > 0 ? cc[i - 1] : ' ';
            char next = i < l - 1 ? cc[i + 1] : ' ';
            if(last == 'a' || next == 'a')
                isa = true;
            if(last == 'b' || next == 'b')
                isb = true;
            if(isa && isb)
                cc[i] = 'c';
            else if(isa && !isb)
                cc[i] = 'b';
            else if(!isa && isb)
                cc[i] = 'a';
            else
                cc[i] = 'a';
        }
        return new String(cc);
    }
}
上一篇:论文解读《The Emerging Field of Signal Processing on Graphs》


下一篇:Proj EULibHarn Paper Reading: Chianina: An Evolving Graph System for Flow- and Context-Sensitive Ana