Leetcode weekly contest
Leetcode weekly conetest 287
1.轉化時間需要的最小運算元
題目大意: 給出兩個時間current和correct(current < correct), 你可以將current時間增加1, 5, 15, 60分鐘, 問將current轉化為correct的最小步驟
解法: 本質上是一個貪心過程,我們儘可能的去將current時間減去當前可撥動的最大分鐘數, 便可以達到最優解。
Code:
class Solution { public: int convert(string time) { char ch0 = time[0], ch1 = time[1], ch3 = time[3], ch4 = time[4]; int hour = (ch0 - '0') * 10 + ch1 - '0', min = (ch3 - '0') * 10 + ch4 - '0'; return hour * 60 + min; } int convertTime(string current, string correct) { int time1 = convert(current); int time2 = convert(correct); int loss = time2 - time1; int cnt = 0; while(loss >= 60) { loss -= 60; cnt++; } while(loss >= 15) { loss -= 15; cnt++; } while(loss >= 5) { loss -= 5; cnt++; } while(loss >= 1) { loss -= 1; cnt++; } return cnt; } };
2.找出輸掉零場或一場比賽的玩家
題目大意:找出比賽過的人裡面,只輸過一場的人或者沒有輸過的人,並將其按照參賽人員序號有序返回。
解法:利用有序容器(Ordered-set)來記錄參賽選手,同時通過雜湊表記錄每名選手的勝利和失敗場次,之後我們便可以遍歷有序容器,按照題意進行處理即可。
Code:
class Solution { public: vector<vector<int>> findWinners(vector<vector<int>>& matches) { unordered_map<int, int> win; //記錄每名參選人的勝利場次 unordered_map<int, int> lose; //記錄每名參選人的失敗場次 set<int> player; //有序容器記錄參選選手的編號,方便後面進行查詢 vector<int> list1; vector<int> list2; for(auto&& x : matches) { win[x[0]]++; lose[x[1]]++; player.insert(x[0]); player.insert(x[1]); } for(auto x : player) { //如果沒參賽,那麼直接跳過 if(lose[x] + win[x] == 0) { continue; } if(lose[x] == 1) { list2.push_back(x); } if(lose[x] == 0) { list1.push_back(x); } } return {list1, list2}; } };
3.每個小孩最多能分到多少糖果
題目大意: 給出一堆糖果,我們將其中的任意一堆拆分,在經過若干次這樣的拆分之後,我們便可以將已經分好的糖果堆發給指定數量的孩子們, 然而處於某種考量,我們必須要讓每個孩子都分配到相同數量的糖果,問每個小孩可以拿到的糖果數量最大是多少。
解法:我們可以做出一種假設,假設我們可以按照每個孩子分給x個糖果來完成分配任務,那麼很簡單的我們就可以推理出,對於每個y,如果 y小於x,那麼我也可以通過給每個孩子y個糖果來完成任務,故在這個答案空間裡,是滿足二分性質的,我們通過列舉上界和下界來進行二分迭代,然後再通過遍歷序列來驗證我們的當前所迭代的數值是否滿足要求即可。
Code:
class Solution {
public:
bool check(vector<int>& c, long long target, long long k) {
//判斷target是否能夠滿足我們的題目要求
long long cnt = 0;
for(int i = 0; i < c.size(); ++i) {
cnt += c[i] / target;
if(cnt >= k) {
return true;
}
}
return false;
}
long long maximumCandies(vector<int>& c, long long k) {
//二分答案 + 遍歷
long long sum = 0;
for(int i = 0; i < c.size(); ++i) {
sum += (long long)c[i];
}
if(sum < k) {
return 0;
}
long long left = 0, right = sum / k + 1; //left和right是我們的上下界限定,為左閉右開區間
while(left < right - 1) {
long long mid = (left + right) / 2;
if(check(c, mid, k)) {
left = mid;
} else {
right = mid;
}
}
return left;
}
};
4.加密解密字串
題目大意:雖然原題目描述有些考驗我們的語文水平,但是加密過程實際上真的只是讓我們對字串(key)中的字元來根據value進行字串替換,而解密則是這一過程的逆過程。
解法: 在比賽中,我的回溯程式碼被無情的TLE了,之後通過靈茶山艾府大佬的題解領悟到十分優雅的思路,即在解密過程中逆向思考,不是去考慮當前字串解密過來之後是什麼樣,而是考慮原字典所有字串加密的時候的所有可能,並將其通過雜湊表記錄下來.
Code:
class Encrypter {
array<string, 26> mp;
unordered_map<string, int> cnt;
public:
Encrypter(vector<char> &keys, vector<string> &values, vector<string> &dictionary) {
for (int i = 0; i < keys.size(); ++i)
mp[keys[i] - 'a'] = values[i];
for (auto &s : dictionary)
++cnt[encrypt(s)];
}
string encrypt(string word1) {
string res;
for (char ch : word1) {
auto &s = mp[ch - 'a'];
if (s == "") return "";
res += s;
}
return res;
}
int decrypt(string word2) { return cnt.count(word2) ? cnt[word2] : 0; }
};