1. 兼具大小写的最好英文字母
难度
- Easy
- Medium
- Hard
完成情况
- 独立完成
- 参考思路
- 参考答案
思路
用一个数组标记下每个字母的大小写形式的出现情况即可,从后往前遍历到第一个两个形式都出现的字母并返回。
代码
class Solution {
public:
string greatestLetter(string s) {
vector<int> vec(26, -1);
for (auto& ch : s) {
if (ch - 'a' >= 0 && ch - 'a' < 26) {
if (vec[ch - 'a'] == -1) vec[ch - 'a'] = 0;
else if (vec[ch - 'a'] == 1) vec[ch - 'a'] = 2;
}
else {
if (vec[ch - 'A'] == -1) vec[ch - 'A'] = 1;
else if (vec[ch - 'A'] == 0) vec[ch - 'A'] = 2;
}
}
string ans = "";
for (int i = 25; i >=0; --i) {
if (vec[i] == 2) {
ans += char('A' + i);
return ans;
}
}
return ans;
}
};
2. 个位数字为 K 的整数之和
难度
- Easy
- Medium
- Hard
完成情况
- 独立完成
- 参考思路
- 参考答案
思路
把问题想复杂了。
列式子看一下,其实num可以表示成10的倍数加上n乘以k的和。因为集合中所有元素都以k为个位数字,那么他们加起来的和一定是n乘以k加上10的倍数。那么只要从小到大遍历n就可以了。要注意num为0和k为0的情况。前者直接返回0,后者应当让k等于10。
其实数学类的题,只要注意到是数学问题,是不难想出来的。
代码
class Solution {
public:
int minimumNumbers(int num, int k) {
if (num == 0) return 0;
if (k == 0) k = 10;
for (int i = 1; i * k <= num; ++i) {
if ((num - i *k) % 10 == 0) return i;
}
return -1;
}
};
3. 小于等于 K 的最长二进制子序列
难度
- Easy
- Medium
- Hard
完成情况
- 独立完成
- 参考思路
- 参考答案
思路
写的比较繁琐,但好歹过了。
要值小于等于目标值,又要求长度最长。注意是子序列,不要求连续,那么前导零当然越多越好。于是先统计每一位左边一共有多少0,然后自左向右遍历,如果当前值再进一步就超过目标值,则停止下来,返回当前长度和左侧0数量的总和。
实际操作过程中,容易发生溢出,所以先计算目标值共有几位,以及当前遍历到的长度,如果长度超过位数,不用计算值,肯定超过了,如果没超过,那么加上对应值即可。
代码
class Solution {
public:
int longestSubsequence(string s, int k) {
int n = s.size();
vector<int> zeroNum(n, 0);
for (int i = 1; i < n; ++i) {
if (s[i - 1] == '0') {
zeroNum[i] = zeroNum[i - 1] + 1;
}
else zeroNum[i] = zeroNum[i - 1];
}
long long num = 0LL;
int pos = 0;
int target = log(k) / log(2);
int j = n - 1;
for (; j >=0; --j) {
if (s[j] == '1') {
if (pos > target) break;
else {
num += 1LL << pos;
if (num > k) break;
}
}
pos += 1;
}
int zero = j < 0 ? 0 : zeroNum[j];
return zero + n - j - 1;
}
};
4. 计算应缴税款总额
难度
- Easy
- Medium
- Hard
完成情况
- 独立完成
- 参考思路
- 参考答案
思路
按部就班计算即可。因为保证了最后一级的上限大于收入,所以也不用考虑超过的情况。
代码
class Solution {
public:
double calculateTax(vector<vector<int>>& brackets, int income) {
int n = brackets.size();
double ans = 0.0;
if (income <= brackets[0][0]) return income * brackets[0][1] * 0.01;
ans += brackets[0][0] * brackets[0][1] * 0.01;
for (int i = 1; i < n; ++i) {
if (income <= brackets[i][0]) {
ans += (income - brackets[i - 1][0]) * brackets[i][1] * 0.01;
break;
}
else {
ans += (brackets[i][0] - brackets[i - 1][0]) * brackets[i][1] * 0.01;
}
}
return ans;
}
};
5. 网格中的最小路径代价
难度
- Easy
- Medium
- Hard
完成情况
- 独立完成
- 参考思路
- 参考答案
思路
DP的思路是用二维数组,记录从第一行到第i行j列元素所用的最小消耗。这样表示之后,后面的逻辑不难得出,最后时间复杂度是m乘以n的平方。而每次我们只关心当前层和上一层,所以空间可以优化。
代码
class Solution {
public:
int minPathCost(vector<vector<int>>& grid, vector<vector<int>>& moveCost) {
int m = grid.size(), n = grid[0].size();
vector<vector<int>> dp(m, vector<int>(n, 0));
for (int i = 0; i < n; ++i) dp[0][i] = grid[0][i];
for (int i = 1; i < m; ++i) {
for (int j = 0; j < n; ++j) {
int minCost = INT_MAX;
for (int k = 0; k < n; ++k) {
int cost = dp[i - 1][k] + moveCost[grid[i - 1][k]][j];
minCost = min(minCost, cost);
}
dp[i][j] = minCost + grid[i][j];
}
}
int ans = INT_MAX;
for (int i = 0; i < n; ++i) {
ans = min(ans, dp[m - 1][i]);
}
return ans;
}
};
6. 公平分发饼干
难度
- Easy
- Medium
- Hard
完成情况
- 独立完成
- 参考思路
- 参考答案
思路
先是感觉类似背包问题,但小朋友的数目会超过两个,无法用背包解。最后用回溯居然擦线过了。但显然还有比较大的剪枝空间。
代码
class Solution {
private:
int ans = INT_MAX;
void backtracking(vector<int>& cookies, int cookie, const int& n, vector<int>& children, const int& k) {
if (cookie == n) {
ans = min(ans, *max_element(children.begin(), children.end()));
return;
}
for (int i = 0; i < k; ++i) {
children[i] += cookies[cookie];
backtracking(cookies, cookie + 1, n, children, k);
children[i] -= cookies[cookie];
}
}
public:
int distributeCookies(vector<int>& cookies, int k) {
ans = INT_MAX;
vector<int> children(k, 0);
backtracking(cookies, 0, cookies.size(), children, k);
return ans;
}
};
7. 公司命名
难度
- Easy
- Medium
- Hard
完成情况
- 独立完成
- 参考思路
- 参考答案
思路
参考这篇 一种比较好理解的思路。
用一个二维数组,记录“用字母B代替一个字母A”对于组中多少字符串是可行的。这个过程中,其实也就统计了“用字母A代替字母B”对于多少字符串是可行的。于是这两种实际上是互补的,是可以作为一个可行解的,于是将两者相乘,最后计算这类互补的累加值即可。
对于字符串类题目,要想到如何用枚举字母的方法做。
代码
class Solution {
public:
long long distinctNames(vector<string>& ideas) {
long long ans = 0L;
unordered_set<string> s(ideas.begin(), ideas.end());
vector<vector<long long>> cnt(26, vector<long long>(26));
for (auto& idea : ideas) {
int pre = idea[0] - 'a';
for (int i = 0; i < 26; ++i) {
idea[0] = 'a' + i;
if (!s.count(idea)) cnt[pre][i]++;
}
}
for (int i = 0; i < 26; ++i) {
for (int j = 0; j < 26; ++j) {
ans += cnt[i][j] * cnt[j][i];
}
}
return ans;
}
};
Comments NOTHING