LeetCode Weekly Contest 175

1346. 检查整数及其两倍数是否存在

给你一个整数数组 arr,请你检查是否存在两个整数 N 和 M,满足 N 是 M 的两倍(即,N = 2 * M)。

更正式地,检查是否存在两个下标 i 和 j 满足:

i != j
0 <= i, j < arr.length
arr[i] == 2 * arr[j]

示例 1:

输入:arr = [10,2,5,3]
输出:true
解释:N = 10 是 M = 5 的两倍,即 10 = 2 * 5 。
示例 2:

输入:arr = [7,1,14,11]
输出:true
解释:N = 14 是 M = 7 的两倍,即 14 = 2 * 7 。
示例 3:

输入:arr = [3,1,7,11]
输出:false
解释:在该情况下不存在 N 和 M 满足 N = 2 * M 。

提示:

2 <= arr.length <= 500
-10^3 <= arr[i] <= 10^3

思路

注意0的2倍仍是0本身,所以要统计数组中0的个数

代码

class Solution {
    public boolean checkIfExist(int[] arr) {
        int num0 = 0;
        HashSet<Integer> set = new HashSet<>();
        for (int a: arr) {
            if (a != 0) {
                set.add(a);
                if (set.contains(a * 2)) {
                    return true;
                }
            } else {
                ++num0;
            }
        }
        if (num0 >= 2) {
            return true;
        }
        for (int a: arr) {
            if (a != 0) {
                if (set.contains(a * 2)) {
                    return true;
                }
            }
        }
        return false;
    }
}

1347. 制造字母异位词的最小步骤数

给你两个长度相等的字符串 s 和 t。每一个步骤中,你可以选择将 t 中的 任一字符 替换为 另一个字符。

返回使 t 成为 s 的字母异位词的最小步骤数。

字母异位词 指字母相同,但排列不同的字符串。

示例 1:

输出:s = “bab”, t = “aba”
输出:1
提示:用 ‘b’ 替换 t 中的第一个 ‘a’,t = “bba” 是 s 的一个字母异位词。
示例 2:

输出:s = “leetcode”, t = “practice”
输出:5
提示:用合适的字符替换 t 中的 ‘p’, ‘r’, ‘a’, ‘i’ 和 ‘c’,使 t 变成 s 的字母异位词。
示例 3:

输出:s = “anagram”, t = “mangaar”
输出:0
提示:“anagram” 和 “mangaar” 本身就是一组字母异位词。
示例 4:

输出:s = “xxyyzz”, t = “xxyyzz”
输出:0
示例 5:

输出:s = “friend”, t = “family”
输出:4

提示:

1 <= s.length <= 50000
s.length == t.length
s 和 t 只包含小写英文字母

思路

用HashMap统计字符串中每个字母出现的次数

代码

class Solution {
    public int minSteps(String s, String t) {
        int[] cnts = new int[26];
        for (char ch: s.toCharArray()) {
            int c = ch - 'a';
            ++cnts[c];
        }
        for (char ch: t.toCharArray()) {
            int c = ch - 'a';
            if (cnts[c] > 0) {
                --cnts[c];
            }
        }
        int ans = 0;
        for (int c: cnts) {
            ans += c;
        }
        return ans;
    }
}

1348. 推文计数

请你实现一个能够支持以下两种方法的推文计数类 TweetCounts

1. recordTweet(string tweetName, int time)

记录推文发布情况:用户 tweetName 在 time(以 秒 为单位)时刻发布了一条推文。

2. getTweetCountsPerFrequency(string freq, string tweetName, int startTime, int endTime)

返回从开始时间 startTime(以 秒 为单位)到结束时间 endTime(以 秒 为单位)内,每 分 minute时 hour 或者 日 day (取决于 freq)内指定用户 tweetName 发布的推文总数。
freq 的值始终为 分 minute时 hour或者 日 day 之一,表示获取指定用户 tweetName 发布推文次数的时间间隔。
第一个时间间隔始终从 startTime 开始,因此时间间隔为 [startTime, startTime + delta*1>, [startTime + delta*1, startTime + delta*2>, [startTime + delta*2, startTime + delta*3>, ... , [startTime + delta*i, min(startTime + delta*(i+1), endTime + 1)>,其中 i 和 delta(取决于 freq)都是非负整数。

示例:

输入:
[“TweetCounts”,“recordTweet”,“recordTweet”,“recordTweet”,“getTweetCountsPerFrequency”,“getTweetCountsPerFrequency”,“recordTweet”,“getTweetCountsPerFrequency”]
[[],[“tweet3”,0],[“tweet3”,60],[“tweet3”,10],[“minute”,“tweet3”,0,59],[“minute”,“tweet3”,0,60],[“tweet3”,120],[“hour”,“tweet3”,0,210]]

输出:
[null,null,null,null,[2],[2,1],null,[4]]

解释:

TweetCounts tweetCounts = new TweetCounts();
tweetCounts.recordTweet("tweet3", 0);
tweetCounts.recordTweet("tweet3", 60);
tweetCounts.recordTweet("tweet3", 10);                             // "tweet3" 发布推文的时间分别是 0, 10 和 60 。
tweetCounts.getTweetCountsPerFrequency("minute", "tweet3", 0, 59); // 返回 [2]。统计频率是每分钟(60 秒),因此只有一个有效时间间隔 [0,60> - > 2 条推文。
tweetCounts.getTweetCountsPerFrequency("minute", "tweet3", 0, 60); // 返回 [2,1]。统计频率是每分钟(60 秒),因此有两个有效时间间隔 1) [0,60> - > 2 条推文,和 2) [60,61> - > 1 条推文。 
tweetCounts.recordTweet("tweet3", 120);                            // "tweet3" 发布推文的时间分别是 0, 10, 60 和 120 。
tweetCounts.getTweetCountsPerFrequency("hour", "tweet3", 0, 210);  // 返回 [4]。统计频率是每小时(3600 秒),因此只有一个有效时间间隔 [0,211> - > 4 条推文。

提示:

同时考虑 recordTweet 和 getTweetCountsPerFrequency,最多有 10000 次操作。
0 <= time, startTime, endTime <= 10^9
0 <= endTime - startTime <= 10^4

思路

模拟题,细节较多,不容易一次做对

代码

class TweetCounts {
    private HashMap<String, ArrayList<Integer>> userTweets = new HashMap<>();
    private HashMap<String, Integer> TIME_FREQ = new HashMap<>();

    public TweetCounts() {
        TIME_FREQ.put("minute", 60);
        TIME_FREQ.put("hour", 3600);
        TIME_FREQ.put("day", 86400);
    }
    
    public void recordTweet(String tweetName, int time) {
        if (!userTweets.containsKey(tweetName)) {
            userTweets.put(tweetName, new ArrayList<Integer>());
        }
        userTweets.get(tweetName).add(time);
    }
    
    public List<Integer> getTweetCountsPerFrequency(String freq, String tweetName, int startTime, int endTime) {
        int sep = TIME_FREQ.get(freq), num = (endTime - startTime)/sep+1;
        Integer[] ans = new Integer[num];
        Arrays.fill(ans, 0);
        if (!userTweets.containsKey(tweetName)) {
            return Arrays.asList(ans);
        }
        ArrayList<Integer> tweets = userTweets.get(tweetName);
        Collections.sort(tweets);
        int left = startTime, right = startTime + sep, cnt = 0, idx = 0, i = 0, n = tweets.size();
        for (i=0; i<n; ++i) {
            int tweet = tweets.get(i);
            if (tweet > endTime) {
                break;
            }
            if (tweet < startTime) {
                continue;
            }
            if (tweet >= left && tweet < right) {
                ++cnt;
            } else {
                ans[idx++] = cnt;
                cnt = 0;
                left = right;
                right += sep;
                --i;
            }
        }
        ans[idx] = cnt;
        return Arrays.asList(ans);
    }
}

/**
 * Your TweetCounts object will be instantiated and called as such:
 * TweetCounts obj = new TweetCounts();
 * obj.recordTweet(tweetName,time);
 * List param_2 = obj.getTweetCountsPerFrequency(freq,tweetName,startTime,endTime);
 */

5335. 参加考试的最大学生数

给你一个 m * n 的矩阵 seats 表示教室中的座位分布。如果座位是坏的(不可用),就用 ‘#’ 表示;否则,用 ‘.’ 表示。
学生可以看到左侧、右侧、左上、右上这四个方向上紧邻他的学生的答卷,但是看不到直接坐在他前面或者后面的学生的答卷。请你计算并返回该考场可以容纳的一起参加考试且无法作弊的最大学生人数。
学生必须坐在状况良好的座位上。

示例 1:
LeetCode Weekly Contest 175_第1张图片
输入:
seats = [["#",".","#","#",".","#"],
[".","#","#","#","#","."],
["#",".","#","#",".","#"]]
输出:4
解释:教师可以让 4 个学生坐在可用的座位上,这样他们就无法在考试中作弊。
示例 2:
输入:
seats = [[".","#"],
["#","#"],
["#","."],
["#","#"],
[".","#"]]
输出:3
解释:让所有学生坐在可用的座位上。
示例 3:
输入:
seats = [["#",".",".",".","#"],
[".","#",".","#","."],
[".",".","#",".","."],
[".","#",".","#","."],
["#",".",".",".","#"]]
输出:10
解释:让学生坐在第 1、3 和 5 列的可用座位上。

提示:

seats 只包含字符 ‘.’ 和’#’
m == seats.length
n == seats[i].length
1 <= m <= 8
1 <= n <= 8

思路

状态压缩动态规划。由于下一行的状态只与上一行有关,所以可以用一维动态规划,每一行的所有可能的状态用二进制压缩。
时间复杂度O(m*n*(2^(n+1))). 其中每次更新一行的状态值时的状态转移需要两层for循环遍历本行状态和上一行状态,遍历了2^n*2^n = 2^(n+1)次,单次状态转移需要遍历每一列,复杂度为O(n),需要进行m-1次这样的状态转移。初始状态的计算只需要遍历一次状态,时间复杂度为O(n*2^n). 因此总的时间复杂度为O(m*n*(2^(n+1))).

代码

class Solution {
    /**
    * Check whether student seat state (state0, state1) and seat situation is valid
    * @param state0: previous row student seat state
    * @param state1: current row student seat state
    * @param row: seat situation of current row
    */
    private boolean checkState(int state0, int state1, char[] row) {
        int col = 0, n = row.length, curLeft = -2;
        for (col=0; col<n; ++col) {
            if ((state1 & (1<<col)) > 0) {
                if (row[col] == '#') {
                    return false;           // student sites on invalid seat
                }
                if (col - curLeft == 1) {
                    return false;           // left student on same row
                }
                if (((col-1>=0) && ((state0 & (1<<(col-1))) > 0)) || ((col+1<n) && ((state0 & (1<<(col+1))) > 0))) {
                    return false;           // left/right student on previous row
                }
                curLeft = col;
            }
        }
        return true;
    }
    
    /**
    * Calculate number of students from row state number
    */
    private int calValue(int state) {
        int ret = 0, i = 1;
        while (i <= state) {
            if ((state & i) > 0) {
                ++ret;
            }
            i <<= 1;
        }
        return ret;
    }
    
    public int maxStudents(char[][] seats) {
        int m = seats.length, n = seats[0].length, state = 0, pres = 0, j = 0, max_state = (1<<n), val = 0;
        int[] dp = new int[max_state], dp1 = new int[max_state];
        for (state=0; state<max_state; ++state) {
            if (checkState(0, state, seats[0])) {
                dp[state] = calValue(state);
            }
        }
        for (j=1; j<m; ++j) {
            // for (state=0; state
            //     System.out.print(dp[state] + ", ");
            // }
            // System.out.println();
            for (state=0; state<max_state; ++state) {
                if (!checkState(0, state, seats[j])) {
                    continue;
                }
                val = calValue(state);
                for (pres = 0; pres<max_state; ++pres) {
                    if (checkState(pres, state, seats[j])) {
                        dp1[state] = Math.max(dp[pres] + val, dp1[state]);
                    }
                }
            }
            // for (state=0; state
            //     System.out.print(dp1[state] + ", ");
            // }
            // System.out.println();
            dp = Arrays.copyOf(dp1, max_state);
            Arrays.fill(dp1, 0);
        }
        val = 0;
        for (state=0; state<max_state; ++state) {
            val = Math.max(val, dp[state]);
        }
        return val;
    }
}

你可能感兴趣的:(LeetCode,周赛,Java,状压dp)