From 2de1a8647fc7eec86042f16bd8191b6dd5b48587 Mon Sep 17 00:00:00 2001 From: programmercarl <826123027@qq.com> Date: Sat, 14 Sep 2024 12:01:45 +0800 Subject: [PATCH] =?UTF-8?q?=E7=A7=BB=E5=8A=A8=E9=9D=9E=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E9=9A=8F=E6=83=B3=E5=BD=95=E4=BD=93=E7=B3=BB=E9=A2=98=E7=9B=AE?= =?UTF-8?q?=E5=88=B0=E5=8D=A1=E7=A0=81=E7=BD=91=E4=BB=93=E5=BA=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kamacoder/0111.构造二阶行列式.md | 27 -- problems/kamacoder/0112.挑战boss.md | 26 -- problems/kamacoder/0113.国际象棋.md | 59 ----- problems/kamacoder/0114.小欧的平均数.md | 29 --- problems/kamacoder/0115.组装手机.md | 67 ----- problems/kamacoder/0121.大数减法.md | 91 ------- .../kamacoder/0121.小红的区间翻转.md | 132 ---------- .../kamacoder/0122.滑动窗口最大值.md | 127 ---------- .../kamacoder/0123.小红的数组构造.md | 52 ---- problems/kamacoder/0124.精华帖子.md | 38 --- .../0125.连续子数组最大和.md | 66 ----- .../kamacoder/0127.小美的排列询问.md | 29 --- problems/kamacoder/0128.小美走公路.md | 35 --- .../kamacoder/0129.小美的蛋糕切割.md | 51 ---- .../0130.小美的字符串变换.md | 78 ------ .../kamacoder/0131.小美的树上染色.md | 134 ---------- problems/kamacoder/0132.夹吃旗.md | 47 ---- .../0134.皇后移动的最小步数.md | 77 ------ .../0135.获取连通的相邻节点列表.md | 147 ----------- problems/kamacoder/0136.字符串处理器.md | 148 ----------- problems/kamacoder/0137.消息传输.md | 192 -------------- problems/kamacoder/0139.可爱串.md | 101 -------- problems/kamacoder/0139.完美数.md | 29 --- problems/kamacoder/0141.好二叉树.md | 104 -------- ...个字符串的最小ASCII删除总和.md | 108 -------- problems/kamacoder/0143.最长同值路径.md | 237 ------------------ .../0144.字典序最小的01字符串.md | 66 ----- .../0145.数组子序列的排列.md | 98 -------- problems/kamacoder/0146.传送树.md | 65 ----- problems/kamacoder/0147.三珠互斥.md | 78 ------ problems/kamacoder/0148.扑克牌同花顺.md | 122 --------- problems/kamacoder/0149.好数组.md | 102 -------- .../0150.极长连续段的权值.md | 66 ----- .../0151.手机流畅运行的秘密.md | 127 ---------- .../0152.小米手机通信校准.md | 121 --------- .../0153.权值优势路径计数.md | 95 ------- problems/kamacoder/0154.序列中位数.md | 68 ----- .../0155.最小化频率的删除代价.md | 106 -------- .../0156.勇敢牛牛战斗序列.md | 68 ----- .../0157.最大化密码复杂度.md | 59 ----- problems/kamacoder/0158.同余方程.md | 50 ---- problems/kamacoder/0159.大整数乘法.md | 62 ----- .../0160.二维平面上的折线段.md | 88 ------- .../0161.讨厌鬼的组合帖子.md | 61 ----- problems/kamacoder/0163.优秀数组.md | 88 ------- problems/kamacoder/0164.升序数组.md | 81 ------ .../0165.最大字典序无重复串.md | 82 ------ 47 files changed, 3984 deletions(-) delete mode 100644 problems/kamacoder/0111.构造二阶行列式.md delete mode 100644 problems/kamacoder/0112.挑战boss.md delete mode 100644 problems/kamacoder/0113.国际象棋.md delete mode 100644 problems/kamacoder/0114.小欧的平均数.md delete mode 100644 problems/kamacoder/0115.组装手机.md delete mode 100644 problems/kamacoder/0121.大数减法.md delete mode 100644 problems/kamacoder/0121.小红的区间翻转.md delete mode 100644 problems/kamacoder/0122.滑动窗口最大值.md delete mode 100644 problems/kamacoder/0123.小红的数组构造.md delete mode 100644 problems/kamacoder/0124.精华帖子.md delete mode 100644 problems/kamacoder/0125.连续子数组最大和.md delete mode 100644 problems/kamacoder/0127.小美的排列询问.md delete mode 100644 problems/kamacoder/0128.小美走公路.md delete mode 100644 problems/kamacoder/0129.小美的蛋糕切割.md delete mode 100644 problems/kamacoder/0130.小美的字符串变换.md delete mode 100644 problems/kamacoder/0131.小美的树上染色.md delete mode 100644 problems/kamacoder/0132.夹吃旗.md delete mode 100644 problems/kamacoder/0134.皇后移动的最小步数.md delete mode 100644 problems/kamacoder/0135.获取连通的相邻节点列表.md delete mode 100644 problems/kamacoder/0136.字符串处理器.md delete mode 100644 problems/kamacoder/0137.消息传输.md delete mode 100644 problems/kamacoder/0139.可爱串.md delete mode 100644 problems/kamacoder/0139.完美数.md delete mode 100644 problems/kamacoder/0141.好二叉树.md delete mode 100644 problems/kamacoder/0142.两个字符串的最小ASCII删除总和.md delete mode 100644 problems/kamacoder/0143.最长同值路径.md delete mode 100644 problems/kamacoder/0144.字典序最小的01字符串.md delete mode 100644 problems/kamacoder/0145.数组子序列的排列.md delete mode 100644 problems/kamacoder/0146.传送树.md delete mode 100644 problems/kamacoder/0147.三珠互斥.md delete mode 100644 problems/kamacoder/0148.扑克牌同花顺.md delete mode 100644 problems/kamacoder/0149.好数组.md delete mode 100644 problems/kamacoder/0150.极长连续段的权值.md delete mode 100644 problems/kamacoder/0151.手机流畅运行的秘密.md delete mode 100644 problems/kamacoder/0152.小米手机通信校准.md delete mode 100644 problems/kamacoder/0153.权值优势路径计数.md delete mode 100644 problems/kamacoder/0154.序列中位数.md delete mode 100644 problems/kamacoder/0155.最小化频率的删除代价.md delete mode 100644 problems/kamacoder/0156.勇敢牛牛战斗序列.md delete mode 100644 problems/kamacoder/0157.最大化密码复杂度.md delete mode 100644 problems/kamacoder/0158.同余方程.md delete mode 100644 problems/kamacoder/0159.大整数乘法.md delete mode 100644 problems/kamacoder/0160.二维平面上的折线段.md delete mode 100644 problems/kamacoder/0161.讨厌鬼的组合帖子.md delete mode 100644 problems/kamacoder/0163.优秀数组.md delete mode 100644 problems/kamacoder/0164.升序数组.md delete mode 100644 problems/kamacoder/0165.最大字典序无重复串.md diff --git a/problems/kamacoder/0111.构造二阶行列式.md b/problems/kamacoder/0111.构造二阶行列式.md deleted file mode 100644 index efb304eb..00000000 --- a/problems/kamacoder/0111.构造二阶行列式.md +++ /dev/null @@ -1,27 +0,0 @@ - -# 111. 构造二阶行列式 - -暴力模拟就好,每个数不超过 20, 暴力枚举其实也没多大。 - -```CPP -#include -using namespace std; -int main() { - int n; - cin >> n; - for (int x = 1; x <= 20; x++) { - for (int y = 1; y <= 20; y++) { - for (int i = 1; i <= 20; i++) { - for (int j = 1; j <= 20; j++) { - if ((x * j - y * i) == n) { - cout << x << " " << y << endl; - cout << i << " " << j << endl; - return 0; - } - } - } - } - } - cout << -1 << endl; -} -``` diff --git a/problems/kamacoder/0112.挑战boss.md b/problems/kamacoder/0112.挑战boss.md deleted file mode 100644 index 781fb6e8..00000000 --- a/problems/kamacoder/0112.挑战boss.md +++ /dev/null @@ -1,26 +0,0 @@ - -# 112. 挑战boss - -本题题意有点绕,注意看一下 题目描述中的【提示信息】,但是在笔试中,是不给这样的提示信息的。 - -简单模拟: - -```CPP -#include -using namespace std; -int main() { - int n, a, b, k = 0; - cin >> n >> a >> b; - string s; - cin >> s; - int result = 0; - for (int i = 0; i < s.size(); i++) { - int cur = a + k * b; - result += cur; - ++k; - if (s[i] == 'x') k = 0; - } - cout << result << endl; - return 0; -} -``` diff --git a/problems/kamacoder/0113.国际象棋.md b/problems/kamacoder/0113.国际象棋.md deleted file mode 100644 index 966aced3..00000000 --- a/problems/kamacoder/0113.国际象棋.md +++ /dev/null @@ -1,59 +0,0 @@ - -# 113.国际象棋 - -广搜,但本题如果广搜枚举马和象的话会超时。 - -广搜要只枚举马的走位,同时判断是否在对角巷直接走象 - -```CPP -#include -using namespace std; -const int N = 100005, mod = 1000000007; -using ll = long long; -int n, ans; -int dir[][2] = {{1, 2}, {1, -2}, {-1, 2}, {-1, -2}, {2, 1}, {2, -1}, {-2, -1}, {-2, 1}}; -int main() { - int x1, y1, x2, y2; - cin >> n; - while (n--) { - scanf("%d%d%d%d", &x1, &y1, &x2, &y2); - if (x1 == x2 && y1 == y2) { - cout << 0 << endl; - continue; - } - // 判断象走一步到达 - int d = abs(x1 - x2) - abs(y1 - y2); - if (!d) {cout << 1 << endl; continue;} - // 判断马走一步到达 - bool one = 0; - for (int i = 0; i < 8; ++i) { - int dx = x1 + dir[i][0], dy = y1 + dir[i][1]; - if (dx == x2 && dy == y2) { - cout << 1 << endl; - one = true; - break; - } - } - if (one) continue; - // 接下来为两步的逻辑, 象走两步或者马走一步,象走一步 - // 象直接两步可以到达,这个计算是不是同颜色的格子,象可以在两步到达所有同颜色的格子 - int d2 = abs(x1 - x2) + abs(y1 - y2); - if (d2 % 2 == 0) { - cout << 2 << endl; - continue; - } - // 接下来判断马 + 象的组合 - bool two = 0; - for (int i = 0; i < 8; ++i) { - int dx = x1 + dir[i][0], dy = y1 + dir[i][1]; - int d = abs(dx - x2) - abs(dy - y2); - if (!d) {cout << 2 << endl; two = true; break;} - } - if (two) continue; - // 剩下的格子全都是三步到达的 - cout << 3 << endl; - } - return 0; -} - -``` diff --git a/problems/kamacoder/0114.小欧的平均数.md b/problems/kamacoder/0114.小欧的平均数.md deleted file mode 100644 index 1188d915..00000000 --- a/problems/kamacoder/0114.小欧的平均数.md +++ /dev/null @@ -1,29 +0,0 @@ - -# 114. 小欧的平均数 - -这道题非常的脑筋急转弯, 读题都要理解半天。 - -初步读题,感觉好像是求 如何最小加减,得到三个数的平均数。 - -但题意不是这样的。 - -小欧的说的三个数平衡,只是三个数里 任何两个数 相加都能被2整除, 那么 也就是说,这三个数 要么都是 奇数,要么都是偶数,才能达到小欧所说的平衡。 - -所以题目要求的,就是,三个数,最小加减1 几次 可以让三个数都变成奇数,或者都变成偶数。 - -所以最终的结果 不是1 就是0,没有其他的。 - -录友可能想,题目出的这么绕干啥? 没办法,企业的笔试题就是这样的。 - -```CPP -#include -#include -using namespace std; -int main() { - int x, y, z; - cin >> x >> y >> z; - int count = (x % 2 == 0) + (y % 2 == 0) + (z % 2 == 0); - cout << min(3 - count, count); -} -``` - diff --git a/problems/kamacoder/0115.组装手机.md b/problems/kamacoder/0115.组装手机.md deleted file mode 100644 index 8cae4a78..00000000 --- a/problems/kamacoder/0115.组装手机.md +++ /dev/null @@ -1,67 +0,0 @@ - -# 115. 组装手机 - -这道题是比较难得哈希表题目。 把代码随想录哈希表章节理解透彻,做本题没问题。 - -思路是 - -1. 用哈希表记录 外壳售价 和 手机零件售价 出现的次数 -2. 记录总和出现的次数 -3. 遍历总和,减去 外壳售价,看 手机零件售价出现了几次 -4. 最后累加,取最大值 - -有一个需要注意的点: 数字可以重复,在计算个数的时候,如果计算重复的数字 - -例如 如果输入是 - -``` -4 -1 1 1 1 -1 1 1 1 -``` -那么输出应该是 4, 外壳售价 和 手机零件售价 是可以重复的。 - -代码如下: - -```CPP -#include -#include -#include -#include -using namespace std; -int main() { - int n; - cin >> n; - vector aVec(n, 0); - vector bVec(n, 0); - unordered_map aUmap; - unordered_map bUmap; - for (int i = 0; i < n; i++) { - cin >> aVec[i]; - aUmap[aVec[i]]++; - } - for (int i = 0; i < n; i++) { - cin >> bVec[i]; - bUmap[bVec[i]]++; - } - unordered_set uset; - for (int i = 0; i < n; i++) { - for (int j = 0; j < n; j++){ - uset.insert(aVec[i] + bVec[j]); - } - } - int result = 0; - for (int sum : uset) { - //cout << p.first << endl; - int count = 0; - for (pair p : aUmap) { - //cout << p.first - aVec[i] << endl; - if (sum - p.first > 0 && bUmap[sum - p.first] != 0) { - count += min(bUmap[sum - p.first], p.second); - } - } - result = max(result, count); - } - cout << result << endl; -} -``` diff --git a/problems/kamacoder/0121.大数减法.md b/problems/kamacoder/0121.大数减法.md deleted file mode 100644 index 84d55249..00000000 --- a/problems/kamacoder/0121.大数减法.md +++ /dev/null @@ -1,91 +0,0 @@ - -

参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们受益!

- -# 大数减法 - -本题测试数据超过int 和 longlong了,所以考察的使用 string 来模拟 两个大数的 加减操作。 - -当然如果使用python或者Java 使用库函数都可以水过。 - -使用字符串来模拟过程,需要处理以下几个问题: - -* 负号处理:要考虑正负数的处理,如果大数相减的结果是负数,需要在结果前加上负号。 -* 大数比较:在进行减法之前,需要确定哪个数大,以便知道结果是否需要添加负号。 -* 位数借位:处理大数相减时的借位问题,这类似于手动减法。 - -```CPP -#include -#include -#include -using namespace std; - -// 比较两个字符串表示的数字,返回1表示a > b,0表示a == b,-1表示a < b -int compareStrings(const string& a, const string& b) { - if (a.length() > b.length()) return 1; - if (a.length() < b.length()) return -1; - return a.compare(b); -} - -// 去除字符串左侧的前导零 -string removeLeadingZeros(const string& num) { - size_t start = 0; - while (start < num.size() && num[start] == '0') { - start++; - } - return start == num.size() ? "0" : num.substr(start); -} - -// 大数相减,假设a >= b -string subtractStrings(const string& a, const string& b) { - string result; - int len1 = a.length(), len2 = b.length(); - int carry = 0; - - for (int i = 0; i < len1; i++) { - int digitA = a[len1 - 1 - i] - '0'; - int digitB = i < len2 ? b[len2 - 1 - i] - '0' : 0; - - int digit = digitA - digitB - carry; - if (digit < 0) { - digit += 10; - carry = 1; - } else { - carry = 0; - } - - result.push_back(digit + '0'); - } - - // 去除结果中的前导零 - reverse(result.begin(), result.end()); - return removeLeadingZeros(result); -} - -string subtractLargeNumbers(const string& num1, const string& num2) { - string a = num1, b = num2; - - // 比较两个数的大小 - int cmp = compareStrings(a, b); - - if (cmp == 0) { - return "0"; // 如果两个数相等,结果为0 - } else if (cmp < 0) { - // 如果a < b,交换它们并在结果前加上负号 - swap(a, b); - return "-" + subtractStrings(a, b); - } else { - return subtractStrings(a, b); - } -} - -int main() { - string num1, num2; - cin >> num1 >> num2; - - string result = subtractLargeNumbers(num1, num2); - cout << result << endl; - - return 0; -} - -``` diff --git a/problems/kamacoder/0121.小红的区间翻转.md b/problems/kamacoder/0121.小红的区间翻转.md deleted file mode 100644 index 6e10aab7..00000000 --- a/problems/kamacoder/0121.小红的区间翻转.md +++ /dev/null @@ -1,132 +0,0 @@ - -# 121. 小红的区间翻转 - -比较暴力的方式,就是直接模拟, 枚举所有 区间,然后检查其翻转的情况。 - -在检查翻转的时候,需要一些代码优化,否则容易超时。 - -```CPP -#include -#include -using namespace std; - -bool canTransform(const vector& a, const vector& b, int left, int right) { - // 提前检查翻转区间的值是否可以匹配 - for (int i = left, j = right; i <= right; i++, j--) { - if (a[i] != b[j]) { - return false; - } - } - // 检查翻转区间外的值是否匹配 - for (int i = 0; i < left; i++) { - if (a[i] != b[i]) { - return false; - } - } - for (int i = right + 1; i < a.size(); i++) { - if (a[i] != b[i]) { - return false; - } - } - return true; -} - -int main() { - int n; - cin >> n; - - vector a(n); - vector b(n); - - for (int i = 0; i < n; i++) { - cin >> a[i]; - } - - for (int i = 0; i < n; i++) { - cin >> b[i]; - } - - int count = 0; - - // 遍历所有可能的区间 - for (int left = 0; left < n; left++) { - for (int right = left; right < n; right++) { - // 检查翻转区间 [left, right] 后,a 是否可以变成 b - if (canTransform(a, b, left, right)) { - count++; - } - } - } - cout << count << endl; - return 0; -} -``` - -也可以事先计算好,最长公共前缀,和最长公共后缀。 - -在公共前缀和公共后缀之间的部分进行翻转操作,这样我们可以减少很多不必要的翻转尝试。 - -通过在公共前缀和后缀之间的部分,找到可以通过翻转使得 a 和 b 相等的区间。 - -以下 为评论区 卡码网用户:码鬼的C++代码 - -```CPP -#include -#include - -using namespace std; - -int main() { - int n; - cin >> n; - vector a(n), b(n); - for (int i = 0; i < n; i++) { - cin >> a[i]; - } - for (int i = 0; i < n; i++) { - cin >> b[i]; - } - - vector prefix(n, 0), suffix(n, 0); - - // 计算前缀相等的位置 - int p = 0; - while (p < n && a[p] == b[p]) { - prefix[p] = 1; - p++; - } - - // 计算后缀相等的位置 - int s = n - 1; - while (s >= 0 && a[s] == b[s]) { - suffix[s] = 1; - s--; - } - - int count = 0; - - // 遍历所有可能的区间 - for (int i = 0; i < n - 1; i++) { - for (int j = i + 1; j < n; j++) { - // 判断前缀和后缀是否相等 - if ((i == 0 || prefix[i - 1] == 1) && (j == n - 1 || suffix[j + 1] == 1)) { - // 判断翻转后的子数组是否和目标数组相同 - bool is_palindrome = true; - for (int k = 0; k <= (j - i) / 2; k++) { - if (a[i + k] != b[j - k]) { - is_palindrome = false; - break; - } - } - if (is_palindrome) { - count++; - } - } - } - } - - cout << count << endl; - - return 0; -} -``` diff --git a/problems/kamacoder/0122.滑动窗口最大值.md b/problems/kamacoder/0122.滑动窗口最大值.md deleted file mode 100644 index 7820d01e..00000000 --- a/problems/kamacoder/0122.滑动窗口最大值.md +++ /dev/null @@ -1,127 +0,0 @@ - -# 滑动窗口最大值 - -本题是 [代码随想录:滑动窗口最大值](https://www.programmercarl.com/0239.%E6%BB%91%E5%8A%A8%E7%AA%97%E5%8F%A3%E6%9C%80%E5%A4%A7%E5%80%BC.html) 的升级版。 - -在[代码随想录:滑动窗口最大值](https://www.programmercarl.com/0239.%E6%BB%91%E5%8A%A8%E7%AA%97%E5%8F%A3%E6%9C%80%E5%A4%A7%E5%80%BC.html) 中详细讲解了如何求解 滑动窗口的最大值。 - -那么求滑动窗口的最小值原理也是一样的, 大家稍加思考,把优先级队列里的 大于 改成小于 就行了。 - -求最大值的优先级队列(从大到小) -``` -while (!que.empty() && value > que.back()) { -``` - -求最小值的优先级队列(从小到大) -``` -while (!que.empty() && value > que.back()) { -``` - -这样在滑动窗口里 最大值最小值都求出来了,遍历一遍找出 差值最大的就好。 - -至于输入,需要一波字符串处理,比较考察基本功。 - -CPP代码如下: - -```CPP -#include -#include -#include -#include -#include -using namespace std; -class MyBigQueue { //单调队列(从大到小) -public: - deque que; // 使用deque来实现单调队列 - // 每次弹出的时候,比较当前要弹出的数值是否等于队列出口元素的数值,如果相等则弹出。 - // 同时pop之前判断队列当前是否为空。 - void pop(int value) { - if (!que.empty() && value == que.front()) { - que.pop_front(); - } - } - // 如果push的数值大于入口元素的数值,那么就将队列后端的数值弹出,直到push的数值小于等于队列入口元素的数值为止。 - // 这样就保持了队列里的数值是单调从大到小的了。 - void push(int value) { - while (!que.empty() && value > que.back()) { - que.pop_back(); - } - que.push_back(value); - - } - // 查询当前队列里的最大值 直接返回队列前端也就是front就可以了。 - int front() { - return que.front(); - } -}; - -class MySmallQueue { //单调队列(从小到大) -public: - deque que; - - void pop(int value) { - if (!que.empty() && value == que.front()) { - que.pop_front(); - } - } - - // 和上面队列的区别是这里换成了小于, - void push(int value) { - while (!que.empty() && value < que.back()) { - que.pop_back(); - } - que.push_back(value); - - } - - int front() { - return que.front(); - } -}; - -int main() { - string input; - - getline(cin, input); - - vector nums; - int k; - - // 找到并截取nums的部分 - int numsStart = input.find('['); - int numsEnd = input.find(']'); - string numsStr = input.substr(numsStart + 1, numsEnd - numsStart - 1); - // cout << numsStr << endl; - - // 用字符串流处理nums字符串,提取数字 - stringstream ss(numsStr); - string temp; - while (getline(ss, temp, ',')) { - nums.push_back(stoi(temp)); - } - - // 找到并提取k的值 - int kStart = input.find("k = ") + 4; - k = stoi(input.substr(kStart)); - - MyBigQueue queB; // 获取区间最大值 - MySmallQueue queS; // 获取区间最小值 - // vector result; - for (int i = 0; i < k; i++) { // 先将前k的元素放进队列 - queB.push(nums[i]); - queS.push(nums[i]); - } - - int result = queB.front() - queS.front(); - for (int i = k; i < nums.size(); i++) { - queB.pop(nums[i - k]); // 滑动窗口移除最前面元素 - queB.push(nums[i]); // 滑动窗口前加入最后面的元素 - - queS.pop(nums[i - k]); - queS.push(nums[i]); - - result = max (result, queB.front() - queS.front()); - } - cout << result << endl; -} -``` diff --git a/problems/kamacoder/0123.小红的数组构造.md b/problems/kamacoder/0123.小红的数组构造.md deleted file mode 100644 index ef66dec8..00000000 --- a/problems/kamacoder/0123.小红的数组构造.md +++ /dev/null @@ -1,52 +0,0 @@ - -121. 小红的数组构造 - -本题大家不要想着真去模拟数组的情况,那样就想复杂了。 - -数组只能是:1k、2k、3k ... (n-1)k、nk,这样 总和就是最小的。 - -注意最后的和可能超过int,所以用 long long。 - -代码如下: - -```CPP -#include -using namespace std; -int main () { - long long result = 0; - int n, k; - cin >> n >> k; - for (int i = 1; i <= n; i++) { - result += i * k; - } - cout << result << endl; -} -``` - -优化思路: - - -由于要计算1到n的整数之和,可以利用等差数列求和公式来优化计算。 - -和公式:1 + 2 + 3 + ... + n = n * (n + 1) / 2 - -因此,总和 result = k * (n * (n + 1) / 2) - -```CPP - -#include -using namespace std; - -int main() { - long long result = 0; - int n, k; - cin >> n >> k; - - // 使用等差数列求和公式进行计算 - result = k * (n * (n + 1LL) / 2); - - cout << result << endl; - return 0; -} - -``` diff --git a/problems/kamacoder/0124.精华帖子.md b/problems/kamacoder/0124.精华帖子.md deleted file mode 100644 index 2855c89e..00000000 --- a/problems/kamacoder/0124.精华帖子.md +++ /dev/null @@ -1,38 +0,0 @@ - - -# 122.精华帖子 - - -开辟一个数组,默认都是0,把精华帖标记为1. - -使用前缀和,快速计算出,k 范围内 有多少个精华帖。 - -前缀和要特别注意区间问题,即 vec[i+k] - vec[i] 求得区间和是 (i, i + k] 这个区间,注意这是一个左开右闭的区间。 - -所以前缀和 很容易漏掉 vec[0] 这个数值的计算 - -```CPP -#include -#include -using namespace std; -int main() { - int n, m, k, l, r; - cin >> n >> m >> k; - vector vec(n); - while (m--) { - cin >> l >> r; - for (int i = l; i < r; i++) vec[i] = 1; - } - int result = 0; - for (int i = 0; i < k; i++) result += vec[i]; // 提前预处理result,包含vec[0]的区间,否则前缀和容易漏掉这个区间 - - for (int i = 1; i < n; i++) { - vec[i] += vec[i - 1]; - } - - for (int i = 0; i < n - k; i++) { - result = max (result, vec[i + k] - vec[i]); - } - cout << result << endl; -} -``` diff --git a/problems/kamacoder/0125.连续子数组最大和.md b/problems/kamacoder/0125.连续子数组最大和.md deleted file mode 100644 index 32833b2f..00000000 --- a/problems/kamacoder/0125.连续子数组最大和.md +++ /dev/null @@ -1,66 +0,0 @@ - -# 123.连续子数组最大和 - -这道题目可以说是 [代码随想录,动态规划:最大子序和](https://www.programmercarl.com/0053.%E6%9C%80%E5%A4%A7%E5%AD%90%E5%BA%8F%E5%92%8C%EF%BC%88%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92%EF%BC%89.html) 的升级版。 - -题目求的是 可以替换一个数字 之后 的 连续子数组最大和。 - -如果替换的是数组下标 i 的元素。 - -那么可以用 [代码随想录,动态规划:最大子序和](https://www.programmercarl.com/0053.%E6%9C%80%E5%A4%A7%E5%AD%90%E5%BA%8F%E5%92%8C%EF%BC%88%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92%EF%BC%89.html) 的方法,先求出 [0 - i) 区间的 最大子序和 dp1 和 (i, n)的最大子序和dp2 。 - -然后在遍历一遍i, 计算 dp1 + dp2 + vec[i] 的最大值就可以。 - -正序遍历,求出 [0 - i) 区间的 最大子序,dp[ i - 1] 表示 是 包括下标i - 1(以vec[i - 1]为结尾)的最大连续子序列和为dp[i - 1]。 - -所以 在计算区间 (i, n)即 dp2 的时候,我们要倒叙。 因为我们求的是以 包括下标i + 1 为起始位置的最大连续子序列和为dp[i + 1]。 - -这样 dp1 + dp2 + vec[i] 才是一个完整区间。 - -这里就体现出对 dp数组定义的把控,本题如果对 dp数组含义理解不清,其实是不容易做出来的。 - -代码: - -```CPP -#include -#include -#include -using namespace std; -int main() { - int t, n, x; - cin >> t; - while (t--) { - cin >> n >> x; - vector vec(n); - for (int i = 0; i < n; i++) cin >> vec[i]; - vector dp1(n); - dp1[0] = vec[0]; - int res = vec[0]; - // 从前向后统计最大子序和 - for (int i = 1; i < n; i++) { - dp1[i] = max(dp1[i - 1] + vec[i], vec[i]); // 状态转移公式 - res = max(res, dp1[i]); - } - - res = max(res, vec[n - 1]); - // 从后向前统计最大子序和 - vector dp2(n); - dp2[n - 1] = vec[n - 1]; - for (int i = n - 2; i >= 0; i--) { - dp2[i] = max(dp2[i + 1] + vec[i], vec[i]); - - } - - for (int i = 0 ; i < n ; i++) { - int dp1res = 0; - if (i > 0) dp1res = max(dp1[i-1], 0); - int dp2res = 0; - if (i < n - 1 ) dp2res = max(dp2[i+1], 0); - - res = max(res, dp1res + dp2res + x); - } - cout << res << endl; - } - -} -``` diff --git a/problems/kamacoder/0127.小美的排列询问.md b/problems/kamacoder/0127.小美的排列询问.md deleted file mode 100644 index 3be7f75b..00000000 --- a/problems/kamacoder/0127.小美的排列询问.md +++ /dev/null @@ -1,29 +0,0 @@ - -# 小美的排列询问 - -模拟题,注意 x 和y 不分先后 - -```CPP - -#include -#include -using namespace std; -int main() { - int n, x, y; - cin >> n; - vector vec(n, 0); - for (int i =0; i < n; i++) { - cin >> vec[i]; - } - cin >> x >> y; - for (int i = 0; i < n - 1; i++) { - if (x == vec[i] && y == vec[i + 1]) || (y == vec[i] && x == vec[i + 1]) ) { - cout << "Yes" << endl; - return 0; - } - } - cout << "No" << endl; - -} - -``` diff --git a/problems/kamacoder/0128.小美走公路.md b/problems/kamacoder/0128.小美走公路.md deleted file mode 100644 index dea68b90..00000000 --- a/problems/kamacoder/0128.小美走公路.md +++ /dev/null @@ -1,35 +0,0 @@ - -# 小美走公路 - -在处理环形情况的时候,很多录友容易算懵了,不是多算一个数,就是少算一个数。 - -这里这样的题目,最好的方式是将 两个环展开,首尾相连,这样我们就可以通过 直线的思维去解题了 - -两个注意点: - -1. x 可以比 y 大,题目没规定 x 和y 的大小顺序 -2. 累计相加的数可能超过int - - -```CPP -#include -#include -using namespace std; -int main () { - int n; - cin >> n; - vector vec(2* n + 1, 0); - for (int i = 1; i <= n; i++) { - cin >> vec[i]; - vec[n + i] = vec[i]; - } - int x, y; - cin >> x >> y; - int xx = min(x ,y); // 注意点1:x 可以比 y 大 - int yy = max(x, y); - long long a = 0, b = 0; // 注意点2:相加的数可能超过int - for (int i = xx; i < yy; i++) a += vec[i]; - for (int i = yy; i < xx + n; i++ ) b += vec[i]; - cout << min(a, b) << endl; -} -``` diff --git a/problems/kamacoder/0129.小美的蛋糕切割.md b/problems/kamacoder/0129.小美的蛋糕切割.md deleted file mode 100644 index ae77478f..00000000 --- a/problems/kamacoder/0129.小美的蛋糕切割.md +++ /dev/null @@ -1,51 +0,0 @@ - -# 小美的蛋糕切割 - -二维前缀和,不了解前缀和的录友 可以自行查一下,是一个很容易理解的算法思路 - -```CPP - -#include -#include -#include - -using namespace std; -int main () { - int n, m; - cin >> n >> m; - int sum = 0; - vector> vec(n, vector(m, 0)) ; - for (int i = 0; i < n; i++) { - for (int j = 0; j < m; j++) { - cin >> vec[i][j]; - sum += vec[i][j]; - } - } - // 统计横向 - vector horizontal(n, 0); - for (int i = 0; i < n; i++) { - for (int j = 0 ; j < m; j++) { - horizontal[i] += vec[i][j]; - } - } - // 统计纵向 - vector vertical(m , 0); - for (int j = 0; j < m; j++) { - for (int i = 0 ; i < n; i++) { - vertical[j] += vec[i][j]; - } - } - int result = INT_MAX; - int horizontalCut = 0; - for (int i = 0 ; i < n; i++) { - horizontalCut += horizontal[i]; - result = min(result, abs(sum - horizontalCut - horizontalCut)); - } - int verticalCut = 0; - for (int j = 0; j < m; j++) { - verticalCut += vertical[j]; - result = min(result, abs(sum - verticalCut - verticalCut)); - } - cout << result << endl; -} -``` diff --git a/problems/kamacoder/0130.小美的字符串变换.md b/problems/kamacoder/0130.小美的字符串变换.md deleted file mode 100644 index 9f9d7899..00000000 --- a/problems/kamacoder/0130.小美的字符串变换.md +++ /dev/null @@ -1,78 +0,0 @@ - -# 130.小美的字符串变换 - -本题是[岛屿数量](./0099.岛屿的数量广搜.md)的进阶版,主要思路和代码都是一样的,统计一个图里岛屿的数量,也是染色问题。 - -1、 先枚举各个可能出现的矩阵 -2、 针对矩阵经行广搜染色(深搜,并查集一样可以) -3、 统计岛屿数量最小的数量。 - -```CPP -#include -#include -#include -#include -using namespace std; - -// 广搜代码同 卡码网:99. 岛屿数量 -int dir[4][2] = {0, 1, 1, 0, -1, 0, 0, -1}; // 四个方向 -void bfs(const vector>& grid, vector>& visited, int x, int y, char a) { - queue> que; - que.push({x, y}); - visited[x][y] = true; // 只要加入队列,立刻标记 - while(!que.empty()) { - pair cur = que.front(); que.pop(); - int curx = cur.first; - int cury = cur.second; - for (int i = 0; i < 4; i++) { - int nextx = curx + dir[i][0]; - int nexty = cury + dir[i][1]; - if (nextx < 0 || nextx >= grid.size() || nexty < 0 || nexty >= grid[0].size()) continue; // 越界了,直接跳过 - if (!visited[nextx][nexty] && grid[nextx][nexty] == a) { - que.push({nextx, nexty}); - visited[nextx][nexty] = true; // 只要加入队列立刻标记 - } - } - } -} - -int main() { - int n; - string s; - cin >> n; - int result = INT_MAX; - cin >> s; - for (int k = 1; k < n; k++) { - if (n % k != 0) continue; - // 计算出 矩阵的 行 和 列 - int x = n / k; - int y = k; - //cout << x << " " << y << endl; - vector> vec(x, vector(y, 0)); - // 填装矩阵 - int sCount = 0; - for (int i = 0; i < x; i++) { - for (int j = 0; j < y; j++) { - vec[i][j] = s[sCount++]; - } - } - - // 开始广搜染色 - vector> visited(x, vector(y, false)); - int count = 0; - for (int i = 0; i < x; i++) { - for (int j = 0; j < y; j++) { - - if (!visited[i][j]) { - count++; // 遇到没访问过的陆地,+1 - bfs(vec, visited, i, j, vec[i][j]); // 将与其链接的陆地都标记上 true - } - } - } - // 取岛屿数量最少的 - result = min (result, count); - - } - cout << result << endl; -} -``` diff --git a/problems/kamacoder/0131.小美的树上染色.md b/problems/kamacoder/0131.小美的树上染色.md deleted file mode 100644 index 36b3c38c..00000000 --- a/problems/kamacoder/0131.小美的树上染色.md +++ /dev/null @@ -1,134 +0,0 @@ -# 131. 小美的树上染色 - -本题为树形dp 稍有难度,主要在于 递推公式上。 - -dp数组的定义: - -dp[cur][1] :当前节点染色,那么当前节点为根节点及其左右子节点中,可以染色的最大数量 - -dp[cur][0] :当前节点不染色,那么当前节点为根节点及其左右子节点中,可以染色的最大数量 - -关于 dp转移方程 - -1、 情况一: - -如果当前节点不染色,那就去 子节点 染色 或者 不染色的最大值。 - -`dp[cur][0] += max(dp[child][0], dp[child][1]);` - - -2、情况二: - -那么当前节点染色的话,这种情况就不好想了。 - -首先这不是二叉树,每一个节点都有可能 会有n个子节点。 - -所以我们要分别讨论,每一个子节点的情况 对父节点的影响。 - -那么父节点 针对每种情况,就要去 最大值, 也就是 `dp[cur][1] = max(dp[cur][1], 每个自孩子的情况)` - -如图,假如节点1 是我们要计算的父节点,节点2是我们这次要计算的子节点。 - -![](https://code-thinking-1253855093.file.myqcloud.com/pics/20240617204601.png) - -选中一个节点2 作为我们这次计算的子节点,父节点染色的话,子节点必染色。 - -接下来就是计算 父节点1和该子节点2染色的话, 以子节点2 为根的 染色节点的最大数量 。 - -是:节点2不染色 且 以节点2为根节点的最大 染色数量 + 2, + 2 是因为 节点 1 和 节点2 要颜色了,染色节点增加两个。 - -代码:`dp[child][0] + 2` - -细心的录友会发现,那我们只计算了 红色框里面的,那么框外 最大的染色数量是多少呢? - -![](https://code-thinking-1253855093.file.myqcloud.com/pics/20240617205709.png) - - -先看 作为子节点的节点2 为根节点的最大染色数量是多少? 取一个最值,即 节点2染色 或者 不染色取最大值。 - -代码:`max(dp[child][0], dp[child][1])` - -那么红框以外的 染色最大节点数量 就是 `dp[cur][0] - max(dp[child][0], dp[child][1])` - -(cur是节点1,child是节点2) - -红框以外的染色最大数量 + 父节点1和该子节点2染色的话 以子节点2 为根的 染色节点的最大数量 就是 节点1 染色的最大节点数量。 - -代码: - -`dp[cur][1] = max(dp[cur][1], dp[cur][0] - max(dp[child][0], dp[child][1]) + dp[child][0] + 2);` - -整体代码如下: - -```CPP - -#include -#include -#include -#include -#include - -using namespace std; - -int maxN = 10005; -vector> dp (maxN, vector(2, 0)); -vector> grid(maxN); // 邻接表 -vector value(maxN); // 存储每个节点的权值 - - -// 在树上进行动态规划的函数 -void dpOnTheTree(int cur) { - - for (int child : grid[cur]) { - // 后序遍历,从下向上计算 - dpOnTheTree(child); - // 情况一 - dp[cur][0] += max(dp[child][0], dp[child][1]); - - } - - // 计算dp[1] - 当前节点染色 - for (int child : grid[cur]) { - long mul = value[cur] * value[child]; // 当前节点和相邻节点权值的乘积 - long sqrtNum = (long) sqrt(mul); - - if (sqrtNum * sqrtNum == mul) { // 如果乘积是完全平方数 - // 情况二 - // dp[cur][0] 表示所有子节点 染色或者不染色的 最大染色数量 - // max(dp[child][0], dp[child][1]) 需要染色节点的孩子节点的最大染色数量 - // dp[cur][0] - max(dp[child][0], dp[child][1]) 除了要染色的节点及其子节点,其他孩子的最大染色数量 - // 最后 + dp[child][0] + 2 , 就是本节点染色的最大染色节点数量 - dp[cur][1] = max(dp[cur][1], dp[cur][0] - max(dp[child][0], dp[child][1]) + dp[child][0] + 2); - } - } - -} - -int main() { - - int n; - cin >> n; // 输入节点数量 - - // 读取节点权值 - for (int i = 1; i <= n; ++i) { - cin >> value[i]; - } - - // 构建树的邻接表 - for (int i = 1; i < n; ++i) { - int x, y; - cin >> x >> y; - grid[x].push_back(y); - } - - // 从根节点(节点1)开始进行动态规划 - dpOnTheTree(1); - - // 输出最大染色节点数量 - cout << max(dp[1][0], dp[1][1]) << endl; - - return 0; -} - -``` - diff --git a/problems/kamacoder/0132.夹吃旗.md b/problems/kamacoder/0132.夹吃旗.md deleted file mode 100644 index 2ec50bfb..00000000 --- a/problems/kamacoder/0132.夹吃旗.md +++ /dev/null @@ -1,47 +0,0 @@ - -# 132. 夹吃棋 - -[题目链接](https://kamacoder.com/problempage.php?pid=1209) - -这道题是模拟题,但很多录友可能想复杂了。 - -行方向,白棋吃,只有这样的布局 `o*o`,黑棋吃,只有这样的布局 `*o*` - -列方向也是同理的。 - -想到这一点,本题的代码就容易写了, C++代码如下: - -```CPP -#include -#include -using namespace std; -int main() { - int n; - cin >> n; - while (n--) { - int black = 0, white = 0; - vector grid(3, ""); - // 判断行 - for (int i = 0; i < 3; i++) { - cin >> grid[i]; - if (grid[i] == "o*o") white++; - if (grid[i] == "*o*") black++; - } - // 判断列 - for (int i = 0; i < 3; i++) { - string s; - s += grid[0][i]; - s += grid[1][i]; - s += grid[2][i]; - if (s == "o*o") white++; - if (s == "*o*") black++; - } - // 如果一个棋盘的局面没有一方被夹吃或者黑白双方都被对面夹吃,则认为是平局 - if ((!white && !black) || (white && black)) cout << "draw" << endl; - // 白棋赢 - else if (white && !black) cout << "yukan" << endl; - // 黑棋赢 - else cout << "kou" << endl; - } -} -``` diff --git a/problems/kamacoder/0134.皇后移动的最小步数.md b/problems/kamacoder/0134.皇后移动的最小步数.md deleted file mode 100644 index ca681df4..00000000 --- a/problems/kamacoder/0134.皇后移动的最小步数.md +++ /dev/null @@ -1,77 +0,0 @@ - -# 134. 皇后移动的最小步数 - -[题目链接](https://kamacoder.com/problempage.php?pid=1211) - -本题和 [代码随想录-不同路径](https://www.programmercarl.com/0062.%E4%B8%8D%E5%90%8C%E8%B7%AF%E5%BE%84.html) 有一些类似。 - -关键是弄清楚递推公式 - -一共分三个情况, - -情况一,向右移动: - -然后从 (i, j) 再向右走 到 (i, k)。 无论k 多大,步数只加1 : - -`dp[i][k] = dp[i][j] + 1` - -那么 `dp[i][k]` 也有可能 从其他方向得到,例如 从上到下, 或者斜上方到达 dp[i][k] - -本题我们要求最小步数,所以取最小值:`dp[i][k] = min(dp[i][k], dp[i][j] + 1);` - -情况二,向下移动: - -从 (i, j) 再向下走 到 (k, j)。 无论k 多大,步数只加1 : - -`dp[k][j] = dp[i][j] + 1;` - -同理 `dp[i][k]` 也有可能 从其他方向得到,取最小值:`dp[k][j] = min(dp[k][j], dp[i][j] + 1);` - -情况三,右下方移动: - -从 (i, j) 再向右下方移动 到 (i + k, j + k)。 无论k 多大,步数只加1 : - -`dp[i + k][j + k] = dp[i][j] + 1` - -同理 `dp[i + k][j + k]` 也有可能 从其他方向得到,取最小值:`dp[i + k][j + k] = min(dp[i + k][j + k], dp[i][j] + 1);` - - -```CPP -#include -#include -using namespace std; -const int INF = 4e6; // 最多步数也就是 2000 * 2000 -int main() { - int n, m; - cin >> n >> m; - vector> grid(n, vector(m)); - for (int i = 0; i < n; i++) { - for (int j = 0; j < m; j++) { - cin >> grid[i][j]; - } - } - vector> dp(n, vector(m, INF)); - dp[0][0] = 0; - for (int i = 0; i < n; i++) { - for (int j = 0; j < m; j++) { - if (grid[i][j] == '*') continue; - // 向右移动k个格子 - for (int k = j + 1; k < m && grid[i][k] == '.'; k++) { - dp[i][k] = min(dp[i][k], dp[i][j] + 1); - } - // 向下移动 k个格子 - for (int k = i + 1; k < n && grid[k][j] == '.'; k++) { - dp[k][j] = min(dp[k][j], dp[i][j] + 1); - } - // 向右下移动k个格子 - for (int k = 1; i + k < n && j + k < m && grid[i + k][j + k] == '.'; k++) { - dp[i + k][j + k] = min(dp[i + k][j + k], dp[i][j] + 1); - } - } - } - if (dp[n - 1][m - 1] == INF) cout << -1 << endl; - else cout << dp[n - 1][m - 1] << endl; -} -``` - - diff --git a/problems/kamacoder/0135.获取连通的相邻节点列表.md b/problems/kamacoder/0135.获取连通的相邻节点列表.md deleted file mode 100644 index c1aa38e1..00000000 --- a/problems/kamacoder/0135.获取连通的相邻节点列表.md +++ /dev/null @@ -1,147 +0,0 @@ - -# 135. 获取连通的相邻节点列表 - -本题是一个 “阅读理解”题,其实题目的算法很简单,但理解题意很费劲。 - -题目描述中的【提示信息】 是我后加上去了,华为笔试的时候没有这个 【提示信息】。 - -相信没有 【提示信息】大家理解题意 平均要多用半个小时。 - -思路: - -1. 将第一行数据加入set中 -2. 后面输出数据,判断是否在 set里 -3. 最后把结果排个序 - - -```CPP -#include -#include -#include -#include -using namespace std; -int main() { - unordered_set uset; - int n, a; - cin >> n; - while (n--) { - cin >> a; - uset.insert(a); - } - int m, x, vlan_id; - long long tb; - vector vecTB; - cin >> m; - while(m--) { - cin >> tb; - cin >> x; - vector vecVlan_id(x); - for (int i = 0; i < x; i++) { - cin >> vecVlan_id[i]; - } - for (int i = 0; i < x; i++) { - if (uset.find(vecVlan_id[i]) != uset.end()) { - vecTB.push_back(tb); - break; - } - } - - } - cout << vecTB.size() << endl; - if (vecTB.size() != 0) { - sort(vecTB.begin(), vecTB.end()); - for (int i = 0; i < vecTB.size() ; i++) cout << vecTB[i] << " "; - } -} - -``` - -## 其他语言版本 - -### Java - -```Java -import java.util.*; - -public class Main { - public static void main(String[] args) { - Scanner scanner = new Scanner(System.in); - Set uset = new HashSet<>(); - int n = scanner.nextInt(); - while (n-- > 0) { - int a = scanner.nextInt(); - uset.add(a); - } - - int m = scanner.nextInt(); - List vecTB = new ArrayList<>(); - while (m-- > 0) { - long tb = scanner.nextLong(); - int x = scanner.nextInt(); - List vecVlan_id = new ArrayList<>(); - for (int i = 0; i < x; i++) { - vecVlan_id.add(scanner.nextInt()); - } - for (int vlanId : vecVlan_id) { - if (uset.contains(vlanId)) { - vecTB.add(tb); - break; - } - } - } - - System.out.println(vecTB.size()); - if (!vecTB.isEmpty()) { - Collections.sort(vecTB); - for (long tb : vecTB) { - System.out.print(tb + " "); - } - } - } -} - -``` - -### Python - -```python -def main(): - import sys - input = sys.stdin.read - data = input().split() - - index = 0 - n = int(data[index]) - index += 1 - uset = set() - for _ in range(n): - a = int(data[index]) - index += 1 - uset.add(a) - - m = int(data[index]) - index += 1 - vecTB = [] - while m > 0: - tb = int(data[index]) - index += 1 - x = int(data[index]) - index += 1 - vecVlan_id = [] - for _ in range(x): - vecVlan_id.append(int(data[index])) - index += 1 - for vlan_id in vecVlan_id: - if vlan_id in uset: - vecTB.append(tb) - break - m -= 1 - - print(len(vecTB)) - if vecTB: - vecTB.sort() - print(" ".join(map(str, vecTB))) - -if __name__ == "__main__": - main() -``` diff --git a/problems/kamacoder/0136.字符串处理器.md b/problems/kamacoder/0136.字符串处理器.md deleted file mode 100644 index 1c58f4ab..00000000 --- a/problems/kamacoder/0136.字符串处理器.md +++ /dev/null @@ -1,148 +0,0 @@ - -# 字符串处理器 - -纯模拟,但情况比较多,非常容易 空指针异常。 - -大家要注意,边界问题 以及 负数问题。 - -整体代码如下: - -```CPP -#include -using namespace std; - int main() { - int index = 0; - long long optNum; - string s; - string cmd; - while(cin >> cmd){ - //cout << s << endl; - if(cmd == "insert") { - string buff; - cin >> buff; - s.insert(index, buff); - index += buff.size(); - } - else if(cmd == "move") { - cin >> optNum; - if(optNum > 0 && index + optNum <= s.size()) index += optNum; - if(optNum < 0 && index >= -optNum) index += optNum; - } - else if(cmd == "delete") { - cin >> optNum; - if(index >= optNum && optNum > 0){ - s.erase(index - optNum, optNum); - index -= optNum; - } - } - else if(cmd == "copy") { - if(index > 0) { - string tmp = s.substr(0, index); - s.insert(index, tmp); - } - } - else if(cmd == "end") { - for(int i = 0; i < index; i++) { - cout << s[i]; - } - cout << '|'; - for(int i = index; i < s.size(); i++) cout << s[i]; - - break; - } - } - return 0; -} - -``` - -## 其他语言版本 - -### Java - -```Java -import java.util.Scanner; - -public class Main { - public static void main(String[] args) { - Scanner scanner = new Scanner(System.in); - StringBuilder s = new StringBuilder(); - int index = 0; - int optNum; - - while (true) { - String cmd = scanner.next(); - if (cmd.equals("insert")) { - String buff = scanner.next(); - s.insert(index, buff); - index += buff.length(); - } else if (cmd.equals("move")) { - optNum = scanner.nextInt(); - if (optNum > 0 && index + optNum <= s.length()) index += optNum; - if (optNum < 0 && index >= -optNum) index += optNum; - } else if (cmd.equals("delete")) { - optNum = scanner.nextInt(); - if (index >= optNum && optNum > 0) { - s.delete(index - optNum, index); - index -= optNum; - } - } else if (cmd.equals("copy")) { - if (index > 0) { - String tmp = s.substring(0, index); - s.insert(index, tmp); - } - } else if (cmd.equals("end")) { - System.out.print(s.substring(0, index) + '|' + s.substring(index)); - break; - } - } - scanner.close(); - } -} -``` - -### Python - -```python -def main(): - import sys - input = sys.stdin.read - data = input().split() - s = "" - index = 0 - i = 0 - - while i < len(data): - cmd = data[i] - i += 1 - if cmd == "insert": - buff = data[i] - i += 1 - s = s[:index] + buff + s[index:] - index += len(buff) - elif cmd == "move": - optNum = int(data[i]) - i += 1 - if optNum > 0 and index + optNum <= len(s): - index += optNum - elif optNum < 0 and index >= -optNum: - index += optNum - elif cmd == "delete": - optNum = int(data[i]) - i += 1 - if index >= optNum and optNum > 0: - s = s[:index - optNum] + s[index:] - index -= optNum - elif cmd == "copy": - if index > 0: - tmp = s[:index] - s = s[:index] + tmp + s[index:] - elif cmd == "end": - print(s[:index] + '|' + s[index:]) - break - -if __name__ == "__main__": - main() - - -``` diff --git a/problems/kamacoder/0137.消息传输.md b/problems/kamacoder/0137.消息传输.md deleted file mode 100644 index a1519bc6..00000000 --- a/problems/kamacoder/0137.消息传输.md +++ /dev/null @@ -1,192 +0,0 @@ - -# 137. 消息传输 - -这道题目,普通广搜就可以解决。 - -这里说一下几点注意事项: - -1、 题目描述中,注意 n 是列数,m是行数 - -这是造成很多录友周赛的时候提交 返回 【运行错误】的罪魁祸首,如果 输入用例是 正方形,那没问题,如果后台输入用例是矩形, n 和 m 搞反了,就会数组越界。 - -矩阵是 m * n ,但输入的顺序却是 先输入n 再输入 m。 - -这会让很多人把矩阵的 n 和 m 搞反。 - -其实规范出题,就应该是n 行,m列,然后 先输入n,在输入m。 - -只能说 大厂出题的人,也不是专业出题的,所以会在 非算法方面一不小心留下很多 “bug”,消耗大家的精力。 - -2、再写广搜的时候,可能担心会无限循环 - -即 A 走到 B,B又走到A,A又走到B ,这种情况,一般来说 广搜都是用一个 visit数组来标记的。 - -但本题不用,因为 不会重复走的,题图里的信号都是正数,根据距离判断大小 可以保证不走回头路。 - -```CPP -#include -#include -#include -using namespace std; -const int inf = 1e6; -int main () { - int n, m, startx, starty; - cin >> n >> m; - cin >> startx >> starty; - vector> grid(m, vector(n)); - vector> dis(m, vector(n, inf)); - for (int i = 0; i < m; i++) { - for (int j = 0; j < n; j++) { - cin >> grid[i][j]; - } - } - queue> que; - int dir[4][2] = {0, 1, 1, 0, -1, 0, 0, -1}; - que.push(pair(startx, starty)); - dis[startx][starty] = 0; - while(!que.empty()) { - pair cur = que.front(); que.pop(); - for (int i = 0; i < 4; i++) { - int newx = cur.first + dir[i][1]; - int newy = cur.second + dir[i][0]; - if (newx < 0 || newx >= m || newy < 0 || newy >= n || grid[cur.first][cur.second] == 0) continue; - - if (dis[newx][newy] > dis[cur.first][cur.second] + grid[cur.first][cur.second]) { - dis[newx][newy] = dis[cur.first][cur.second] + grid[cur.first][cur.second]; - que.push(pair(newx, newy)); - } - } - } - int result = 0; - for (int i = 0; i < m; i++) { - for (int j = 0; j < n; j++) { - if (dis[i][j] == inf) { - cout << -1 << endl; - return 0; - } - result = max(result, dis[i][j]); - } - } - cout << result << endl; -} -``` - -## 其他语言版本 - -### Java - -```Java -import java.util.*; - -public class Main { - static final int INF = 1000000; - - public static void main(String[] args) { - Scanner scanner = new Scanner(System.in); - int n = scanner.nextInt(); - int m = scanner.nextInt(); - int startX = scanner.nextInt(); - int startY = scanner.nextInt(); - - int[][] grid = new int[m][n]; - int[][] dis = new int[m][n]; - - for (int i = 0; i < m; i++) { - Arrays.fill(dis[i], INF); - for (int j = 0; j < n; j++) { - grid[i][j] = scanner.nextInt(); - } - } - - Queue queue = new LinkedList<>(); - int[][] directions = {{0, 1}, {1, 0}, {-1, 0}, {0, -1}}; - - queue.add(new int[]{startX, startY}); - dis[startX][startY] = 0; - - while (!queue.isEmpty()) { - int[] current = queue.poll(); - for (int[] dir : directions) { - int newX = current[0] + dir[0]; - int newY = current[1] + dir[1]; - if (newX >= 0 && newX < m && newY >= 0 && newY < n && grid[current[0]][current[1]] != 0) { - if (dis[newX][newY] > dis[current[0]][current[1]] + grid[current[0]][current[1]]) { - dis[newX][newY] = dis[current[0]][current[1]] + grid[current[0]][current[1]]; - queue.add(new int[]{newX, newY}); - } - } - } - } - - int result = 0; - for (int i = 0; i < m; i++) { - for (int j = 0; j < n; j++) { - if (dis[i][j] == INF) { - System.out.println(-1); - return; - } - result = Math.max(result, dis[i][j]); - } - } - - System.out.println(result); - scanner.close(); - } -} -``` - -### Python - -```Python -from collections import deque - -inf = 1000000 - -def main(): - import sys - input = sys.stdin.read - data = input().split() - index = 0 - - n = int(data[index]) - m = int(data[index+1]) - startx = int(data[index+2]) - starty = int(data[index+3]) - index += 4 - - grid = [] - dis = [[inf] * n for _ in range(m)] - - for i in range(m): - grid.append([int(data[index+j]) for j in range(n)]) - index += n - - directions = [(0, 1), (1, 0), (-1, 0), (0, -1)] - queue = deque() - queue.append((startx, starty)) - dis[startx][starty] = 0 - - while queue: - curx, cury = queue.popleft() - for dx, dy in directions: - newx, newy = curx + dx, cury + dy - if 0 <= newx < m and 0 <= newy < n and grid[curx][cury] != 0: - if dis[newx][newy] > dis[curx][cury] + grid[curx][cury]: - dis[newx][newy] = dis[curx][cury] + grid[curx][cury] - queue.append((newx, newy)) - - result = 0 - for i in range(m): - for j in range(n): - if dis[i][j] == inf: - print(-1) - return - result = max(result, dis[i][j]) - - print(result) - -if __name__ == "__main__": - main() - - -``` diff --git a/problems/kamacoder/0139.可爱串.md b/problems/kamacoder/0139.可爱串.md deleted file mode 100644 index 9ff0b684..00000000 --- a/problems/kamacoder/0139.可爱串.md +++ /dev/null @@ -1,101 +0,0 @@ - -# 可爱串 - -整体思路,就含有 子序列的字符串数量 减去 含有子串的字符串数量。 - -因为子序列数量已经是包含子串数量的。 剩下的就是 只有子序列 且没有子串的 字符串数量。 - - -需要注意我们求的不是 长度为 i 的字符串里有多少个 red 子序列。 - -**而是 可以有多少个 长度为i 的字符串 含有子序列 red** - -同理,可以有多少个长度为i的字符串含有 red 子串 - -认清这一点很重要! - -### 求子串 - -dp2[i][3] 长度为i 且 含有子串 red 的字符串数量 有多少 - -dp2[i][2] 长度为i 且 含有子串 re 的字符串数量有多少 - -dp2[i][1] 长度为 i 且 含有子串 r 的字符串数量有多少 - -dp2[1][0] 长度为 i 且 含有 只有 de, ee , e, d的字符串的字符串数量有多少。 - -```CPP -// 求子串 -dp2[0][0] = 1; -for(int i = 1;i <= n; i++) { - dp2[i][0] = (dp2[i - 1][2] + dp2[i - 1][1] + dp2[i - 1][0] * 2) % mod; // 含有 re 的可以把 r改成d, 含有r 的可以改成 - dp2[i][1] = (dp2[i - 1][2] + dp2[i - 1][1] + dp2[i - 1][0]) % mod; - dp2[i][2] = (dp2[i - 1][1]); - dp2[i][3] = (dp2[i - 1][3] * 3 + dp2[i - 1][2]) % mod; -} -`` - -### 求子序列 - -dp1[i][3] 长度为i 且 含有子序列 red 的字符串数量 有多少 - -dp2[i][2] 长度为i 且 含有子序列 re 的字符串数量有多少 - -dp2[i][1] 长度为 i 且 含有子序列 r 的字符串数量有多少 - -dp2[1][0] 长度为 i 且 含有 只含有 e 和 d 的字符串的字符串数量有多少。 - -```CPP - -// 求子序列 -dp1[0][0]=1; -for(int i=1;i<=n;i++) -{ - dp1[i][0] = (dp1[i - 1][0] * 2) % mod; - dp1[i][1] = (dp1[i - 1][0] + dp1[i - 1][1] * 2) % mod; - dp1[i][2] = (dp1[i - 1][1] + dp1[i - 1][2] * 2) % mod; - dp1[i][3] = (dp1[i - 1][2] + dp1[i - 1][3] * 3) % mod; -} -``` - - - -```CPP - -#include -using namespace std; - -using ll=long long; -const int mod=1e9+7; - -int main() -{ - int n; - - cin>>n; - vector> dp1(n + 1,vector (4,0)); - vector> dp2(n + 1,vector (4,0)); - // 求子串 - dp2[0][0] = 1; - for(int i = 1;i <= n; i++) { - dp2[i][0] = (dp2[i - 1][2] + dp2[i - 1][1] + dp2[i - 1][0] * 2) % mod; - dp2[i][1] = (dp2[i - 1][2] + dp2[i - 1][1] + dp2[i - 1][0]) % mod; - dp2[i][2] = (dp2[i - 1][1]); - dp2[i][3] = (dp2[i - 1][3] * 3 + dp2[i - 1][2]) % mod; - } - - // 求子序列 - dp1[0][0]=1; - for(int i=1;i<=n;i++) - { - dp1[i][0] = (dp1[i - 1][0] * 2) % mod; - dp1[i][1] = (dp1[i - 1][0] + dp1[i - 1][1] * 2) % mod; - dp1[i][2] = (dp1[i - 1][1] + dp1[i - 1][2] * 2) % mod; - dp1[i][3] = (dp1[i - 1][2] + dp1[i - 1][3] * 3) % mod; - } - - cout<<(dp1[n][3] - dp2[n][3])%mod; - -} - -``` diff --git a/problems/kamacoder/0139.完美数.md b/problems/kamacoder/0139.完美数.md deleted file mode 100644 index 1f801d76..00000000 --- a/problems/kamacoder/0139.完美数.md +++ /dev/null @@ -1,29 +0,0 @@ - -```CPP -#include -#include -using namespace std; -int countOnes(long long num) { - int zeroCount = 0; - while (num > 0) { - if (num % 10 != 0) { // 检查最低位是否为0 - zeroCount++; - } - num /= 10; // 移除最低位 - } - return zeroCount; -} -int main() { - int n; - cin >> n; - vector vec(n); - for (int i = 0; i < n; i++) cin >> vec[i]; - int result = 0; - for (int i = 0; i < n; i++) { - for (int j = i + 1; j < n; j++) { - if (countOnes(vec[i] * vec[j]) == 1) result++; - } - } - cout << result << endl; -} -``` diff --git a/problems/kamacoder/0141.好二叉树.md b/problems/kamacoder/0141.好二叉树.md deleted file mode 100644 index fe48f2fd..00000000 --- a/problems/kamacoder/0141.好二叉树.md +++ /dev/null @@ -1,104 +0,0 @@ - -本题和 [96.不同的二叉搜索树](https://www.programmercarl.com/0096.%E4%B8%8D%E5%90%8C%E7%9A%84%E4%BA%8C%E5%8F%89%E6%90%9C%E7%B4%A2%E6%A0%91.html) 比较像 - -* 取模这里很容易出错 -* 过程中所用到的数值都有可能超过int,所以要改用longlong - -```CPP -#include -#include -using namespace std; - -long long mod = 1e9 + 7; -long long dp(int t, vector& memory) { - if (t % 2 == 0) return 0; - if (t == 1) return 1; - if (memory[t] != -1) return memory[t]; - - long long result = 0; - // 枚举左右子树节点的数量 - for (int i = 1; i < t; i += 2) { - long long leftNum = dp(i, memory); // 左子树节点数量为i - long long rightNum = dp(t - i - 1, memory); // 右子树节点数量为t - i - 1 - result += (leftNum * rightNum) % mod; // 注意这里是乘的关系 - result %= mod; - } - memory[t] = result; - return result; -} -int main() { - int n; - cin >> n; - vector memory(n + 1, -1); - cout << dp(n, memory) << endl; -} -``` - - -```CPP -#include -#include -#include - -using namespace std; - -const int MOD = 1000000007; - -int main() { - int num; - cin >> num; - - if (num % 2 == 0) { - cout << 0 << endl; - return 0; - } - - vector dp(num + 1, 0); - dp[1] = 1; - - for (int i = 3; i <= num; i += 2) { - for (int j = 1; j <= i - 2; j += 2) { - dp[i] = (dp[i] + dp[j] * dp[i - 1 - j]) % MOD; - } - } - - cout << dp[num] << endl; - return 0; -} - -``` - - -第二题的代码 - -#include -using namespace std; - -long fastexp(long base,long n,long mod){ - long answer = 1; - while(n > 0){ - if(n % 2 == 1){ - answer = (answer * base) % mod; - } - base = (base * base) % mod; - n /= 2; - } - return answer; -} -int kawaiiStrings(int n) { - // write code here - std::vector f(n + 1), g(n + 1), h(n + 1); - long mod = 1000000007; - for (long i = 2; i <= n; i++) g[i] = (g[i - 1] * 2 + (i - 1) * fastexp(2,i-2,mod)) % mod; - for (long i = 3; i <= n; i++) f[i] = ((f[i - 1] * 3) % mod + g[i - 1]) % mod; - for (long i = 3; i <= n; i++) h[i] = (fastexp(3, i - 3, mod) + h[i - 1] * 3 - h[i - 3]) % mod; - return (f[n]-h[n]+mod)%mod; - -} - -int main(){ - int n; - cin >> n; - cout << kawaiiStrings(n) << endl; - return 0; -} diff --git a/problems/kamacoder/0142.两个字符串的最小ASCII删除总和.md b/problems/kamacoder/0142.两个字符串的最小ASCII删除总和.md deleted file mode 100644 index ff34581f..00000000 --- a/problems/kamacoder/0142.两个字符串的最小ASCII删除总和.md +++ /dev/null @@ -1,108 +0,0 @@ - -# 142. 两个字符串的最小 ASCII 删除总和 - -本题和[代码随想录:两个字符串的删除操作](https://www.programmercarl.com/0583.%E4%B8%A4%E4%B8%AA%E5%AD%97%E7%AC%A6%E4%B8%B2%E7%9A%84%E5%88%A0%E9%99%A4%E6%93%8D%E4%BD%9C.html) 思路基本是一样的。 - -属于编辑距离问题,如果想彻底了解,建议看看「代码随想录」的编辑距离总结篇。 - -本题dp数组含义: - -dp[i][j] 表示 以i-1为结尾的字符串word1,和以j-1位结尾的字符串word2,想要达到相等,所需要删除元素的最小ASCII 删除总和。 - -如果 s1[i - 1] 与 s2[j - 1] 相同,则不用删:`dp[i][j] = dp[i - 1][j - 1]` - -如果 s1[i - 1] 与 s2[j - 1] 不相同,删word1 的 最小删除和: `dp[i - 1][j] + s1[i - 1]` ,删word2的最小删除和: `dp[i][j - 1] + s2[j - 1]` - -取最小值: `dp[i][j] = min(dp[i - 1][j] + s1[i - 1], dp[i][j - 1] + s2[j - 1])` - - - -```CPP -#include -#include -using namespace std; -int main() { - string s1, s2; - cin >> s1 >> s2; - vector> dp(s1.size() + 1, vector(s2.size() + 1, 0)); - - // s1 如果变成空串的最小删除ASCLL值综合 - for (int i = 1; i <= s1.size(); i++) dp[i][0] = dp[i - 1][0] + s1[i - 1]; - // s2 如果变成空串的最小删除ASCLL值综合 - for (int j = 1; j <= s2.size(); j++) dp[0][j] = dp[0][j - 1] + s2[j - 1]; - - for (int i = 1; i <= s1.size(); i++) { - for (int j = 1; j <= s2.size(); j++) { - if (s1[i - 1] == s2[j - 1]) dp[i][j] = dp[i - 1][j - 1]; - else dp[i][j] = min(dp[i - 1][j] + s1[i - 1], dp[i][j - 1] + s2[j - 1]); - } - } - cout << dp[s1.size()][s2.size()] << endl; -} -``` - -### Java - -```Java -import java.util.Scanner; - -public class Main { - public static void main(String[] args) { - Scanner scanner = new Scanner(System.in); - String s1 = scanner.nextLine(); - String s2 = scanner.nextLine(); - int[][] dp = new int[s1.length() + 1][s2.length() + 1]; - - // s1 如果变成空串的最小删除ASCII值综合 - for (int i = 1; i <= s1.length(); i++) { - dp[i][0] = dp[i - 1][0] + s1.charAt(i - 1); - } - // s2 如果变成空串的最小删除ASCII值综合 - for (int j = 1; j <= s2.length(); j++) { - dp[0][j] = dp[0][j - 1] + s2.charAt(j - 1); - } - - for (int i = 1; i <= s1.length(); i++) { - for (int j = 1; j <= s2.length(); j++) { - if (s1.charAt(i - 1) == s2.charAt(j - 1)) { - dp[i][j] = dp[i - 1][j - 1]; - } else { - dp[i][j] = Math.min(dp[i - 1][j] + s1.charAt(i - 1), dp[i][j - 1] + s2.charAt(j - 1)); - } - } - } - System.out.println(dp[s1.length()][s2.length()]); - scanner.close(); - } -} - - -``` - -### python - -```python -def min_delete_sum(s1: str, s2: str) -> int: - dp = [[0] * (len(s2) + 1) for _ in range(len(s1) + 1)] - - # s1 如果变成空串的最小删除ASCII值综合 - for i in range(1, len(s1) + 1): - dp[i][0] = dp[i - 1][0] + ord(s1[i - 1]) - # s2 如果变成空串的最小删除ASCII值综合 - for j in range(1, len(s2) + 1): - dp[0][j] = dp[0][j - 1] + ord(s2[j - 1]) - - for i in range(1, len(s1) + 1): - for j in range(1, len(s2) + 1): - if s1[i - 1] == s2[j - 1]: - dp[i][j] = dp[i - 1][j - 1] - else: - dp[i][j] = min(dp[i - 1][j] + ord(s1[i - 1]), dp[i][j - 1] + ord(s2[j - 1])) - - return dp[len(s1)][len(s2)] - -if __name__ == "__main__": - s1 = input().strip() - s2 = input().strip() - print(min_delete_sum(s1, s2)) -``` diff --git a/problems/kamacoder/0143.最长同值路径.md b/problems/kamacoder/0143.最长同值路径.md deleted file mode 100644 index bf46c895..00000000 --- a/problems/kamacoder/0143.最长同值路径.md +++ /dev/null @@ -1,237 +0,0 @@ - - -# 143. 最长同值路径 - - -本题两个考点: - -1. 层序遍历构造二叉树 -2. 树形dp,找出最长路径 - -对于写代码不多,或者动手能力比较差的录友,第一个 构造二叉树 基本就被卡主了。 - -```CPP -#include -#include -#include - -using namespace std; - -// 定义二叉树节点结构 -struct TreeNode { - int val; - TreeNode* left; - TreeNode* right; - TreeNode(int x) : val(x), left(NULL), right(NULL) {} -}; - -// 根据层序遍历数组构建二叉树 -TreeNode* constructBinaryTree(const vector& levelOrder) { - if (levelOrder.empty()) return NULL; - - TreeNode* root = new TreeNode(stoi(levelOrder[0])); - queue q; - q.push(root); - int i = 1; - - while (!q.empty() && i < levelOrder.size()) { - TreeNode* current = q.front(); - q.pop(); - - if (i < levelOrder.size() && levelOrder[i] != "null") { - current->left = new TreeNode(stoi(levelOrder[i])); - q.push(current->left); - } - i++; - - if (i < levelOrder.size() && levelOrder[i] != "null") { - current->right = new TreeNode(stoi(levelOrder[i])); - q.push(current->right); - } - i++; - } - - return root; -} - -int result = 0; - -// 树形DP -int dfs(TreeNode* node) { - if (node == NULL) return 0; - int leftPath = dfs(node->left); - int rightPath = dfs(node->right); - - int leftNum = 0, rightNum = 0; - if (node->left != NULL && node->left->val == node->val) { - leftNum = leftPath + 1; - } - if (node->right != NULL && node->right->val == node->val) { - rightNum = rightPath + 1; - } - result = max(result, leftNum + rightNum); - return max(leftNum, rightNum); - -} - - -int main() { - int n; - cin >> n; - vector levelOrder(n); - for (int i = 0; i < n ; i++) cin >> levelOrder[i]; - - TreeNode* root = constructBinaryTree(levelOrder); - dfs(root); - cout << result << endl; - - return 0; -} -``` - -### Java - -```Java -import java.util.*; - -class TreeNode { - int val; - TreeNode left, right; - TreeNode(int x) { - val = x; - left = null; - right = null; - } -} - -public class Main { - public static int result = 0; - - public static TreeNode constructBinaryTree(List levelOrder) { - if (levelOrder.isEmpty()) return null; - - TreeNode root = new TreeNode(Integer.parseInt(levelOrder.get(0))); - Queue queue = new LinkedList<>(); - queue.add(root); - int i = 1; - - while (!queue.isEmpty() && i < levelOrder.size()) { - TreeNode current = queue.poll(); - - if (i < levelOrder.size() && !levelOrder.get(i).equals("null")) { - current.left = new TreeNode(Integer.parseInt(levelOrder.get(i))); - queue.add(current.left); - } - i++; - - if (i < levelOrder.size() && !levelOrder.get(i).equals("null")) { - current.right = new TreeNode(Integer.parseInt(levelOrder.get(i))); - queue.add(current.right); - } - i++; - } - - return root; - } - - public static int dfs(TreeNode node) { - if (node == null) return 0; - int leftPath = dfs(node.left); - int rightPath = dfs(node.right); - - int leftNum = 0, rightNum = 0; - if (node.left != null && node.left.val == node.val) { - leftNum = leftPath + 1; - } - if (node.right != null && node.right.val == node.val) { - rightNum = rightPath + 1; - } - result = Math.max(result, leftNum + rightNum); - return Math.max(leftNum, rightNum); - } - - public static void main(String[] args) { - Scanner sc = new Scanner(System.in); - int n = sc.nextInt(); - sc.nextLine(); // consume the newline character - List levelOrder = new ArrayList<>(); - for (int i = 0; i < n; i++) { - levelOrder.add(sc.next()); - } - TreeNode root = constructBinaryTree(levelOrder); - dfs(root); - System.out.println(result); - sc.close(); - } -} - -``` - -### python - -```python -from typing import List, Optional -from collections import deque -import sys - -class TreeNode: - def __init__(self, val: int = 0, left: 'TreeNode' = None, right: 'TreeNode' = None): - self.val = val - self.left = left - self.right = right - -def construct_binary_tree(level_order: List[str]) -> Optional[TreeNode]: - if not level_order: - return None - - root = TreeNode(int(level_order[0])) - queue = deque([root]) - i = 1 - - while queue and i < len(level_order): - current = queue.popleft() - - if i < len(level_order) and level_order[i] != "null": - current.left = TreeNode(int(level_order[i])) - queue.append(current.left) - i += 1 - - if i < len(level_order) and level_order[i] != "null": - current.right = TreeNode(int(level_order[i])) - queue.append(current.right) - i += 1 - - return root - -result = 0 - -def dfs(node: Optional[TreeNode]) -> int: - global result - if node is None: - return 0 - - left_path = dfs(node.left) - right_path = dfs(node.right) - - left_num = right_num = 0 - if node.left is not None and node.left.val == node.val: - left_num = left_path + 1 - if node.right is not None and node.right.val == node.val: - right_num = right_path + 1 - - result = max(result, left_num + right_num) - return max(left_num, right_num) - -if __name__ == "__main__": - input = sys.stdin.read - data = input().strip().split() - - n = int(data[0]) - level_order = data[1:] - - root = construct_binary_tree(level_order) - dfs(root) - print(result) - - -``` diff --git a/problems/kamacoder/0144.字典序最小的01字符串.md b/problems/kamacoder/0144.字典序最小的01字符串.md deleted file mode 100644 index 1528fdbd..00000000 --- a/problems/kamacoder/0144.字典序最小的01字符串.md +++ /dev/null @@ -1,66 +0,0 @@ - -# 0144.字典序最小的01字符串 - -贪心思路:移动尽可能 移动前面的1 ,这样可以是 字典序最小 - -从前到后遍历,遇到 0 ,就用前面的 1 来交换 - -```CPP -#include -#include -using namespace std; -int main() { - int n,k; - cin >> n >> k; - string s; - cin >> s; - for(int i = 0; i < n && k > 0; i++) { - if(s[i] == '0') { - // 开始用前面的 1 来交换 - int j = i; - while(j > 0 && s[j - 1] == '1' && k > 0) { - swap(s[j], s[j - 1]); - --j; - --k; - } - } - } - cout << s << endl; - return 0; -} - -``` - -Java: - -```Java - -import java.util.*; - -public class Main { - public static void main(String[] args) { - Scanner scanner = new Scanner(System.in); - int n = scanner.nextInt(); - int k = scanner.nextInt(); - scanner.nextLine(); // 消耗掉换行符 - String s = scanner.nextLine(); - char[] ch = s.toCharArray(); - - for (int i = 0; i < n && k > 0; i++) { - if (ch[i] == '0') { - // 开始用前面的 1 来交换 - int j = i; - while (j > 0 && ch[j - 1] == '1' && k > 0) { - char tmp = ch[j]; - ch[j] = ch[j - 1]; - ch[j - 1] = tmp; - j--; - k--; - } - } - } - - System.out.println(new String(ch)); - } -} -``` diff --git a/problems/kamacoder/0145.数组子序列的排列.md b/problems/kamacoder/0145.数组子序列的排列.md deleted file mode 100644 index 757fe0b2..00000000 --- a/problems/kamacoder/0145.数组子序列的排列.md +++ /dev/null @@ -1,98 +0,0 @@ - -# 145. 数组子序列的排列 - -每个元素出现的次数相乘就可以了。 - -注意 “长度为 m 的数组,1 到 m 每个元素都出现过,且恰好出现 1 次。” ,题目中有n个元素,所以我们要统计的就是 1 到 n 元素出现的个数。 - -因为如果有一个元素x 大于n了, 那不可能出现 长度为x的数组 且 1 到 x 每个元素都出现过。 - -```CPP -#include "bits/stdc++.h" -using namespace std; -int main(){ - int n; - int x; - cin >> n; - unordered_map umap; - for(int i = 0; i < n; ++i){ - cin >> x; - if(umap.find(x) != umap.end()) umap[x]++; - else umap[x] = 1; - } - long long res = 0; - long long num = 1; - for (int i = 1; i <= n; i++) { - if (umap.find(i) == umap.end()) break; // 如果i都没出现,后面得数也不能 1 到 m 每个元素都出现过 - num = (num * umap[i]) % 1000000007; - res += num; - res %= 1000000007; - } - cout << res << endl; -} - -``` - -```Java - -import java.util.HashMap; -import java.util.Map; -import java.util.Scanner; - -public class Main { - public static void main(String[] args) { - Scanner sc = new Scanner(System.in); - int n = sc.nextInt(); - Map map = new HashMap<>(); - for (int i = 0; i < n; i++) { - int x = sc.nextInt(); - map.put(x, map.getOrDefault(x, 0) + 1); - } - long res = 0; - long num = 1; - for (int i = 1; i <= n; i++) { - if (!map.containsKey(i)) break; // 如果i都没出现,后面得数也不能1到m每个元素都出现过 - num = (num * map.get(i)) % 1000000007; - res += num; - res %= 1000000007; - } - System.out.println(res); - sc.close(); - } -} - -``` - - -```python -def main(): - import sys - input = sys.stdin.read - data = input().split() - - n = int(data[0]) - umap = {} - - for i in range(1, n + 1): - x = int(data[i]) - if x in umap: - umap[x] += 1 - else: - umap[x] = 1 - - res = 0 - num = 1 - MOD = 1000000007 - - for i in range(1, n + 1): - if i not in umap: - break # 如果i都没出现,后面得数也不能1到m每个元素都出现过 - num = (num * umap[i]) % MOD - res = (res + num) % MOD - - print(res) - -if __name__ == "__main__": - main() - -``` diff --git a/problems/kamacoder/0146.传送树.md b/problems/kamacoder/0146.传送树.md deleted file mode 100644 index 4cafb040..00000000 --- a/problems/kamacoder/0146.传送树.md +++ /dev/null @@ -1,65 +0,0 @@ - - - - -# 146. 传送树 - -本题题意是比较绕的,我后面给补上了 【提示信息】对 题目输出样例讲解一下,相对会容易理解的多。 - -```CPP -#include -#include -#include -using namespace std; - -vector> edge; // 邻接表来存图 -vector nxt; -int n; - -/* - * 递归函数,用于找到每个节点的下一个传送门节点,并记录在nxt数组中。 - * 遍历当前节点的所有子节点,递归调用findNext以确保子节点的nxt值已经计算出来。 - * 更新当前节点的nxt值为其子节点中编号最小的节点。 - * 如果当前节点是叶子节点(即没有子节点),则将其nxt值设置为自身。 - */ -void findNext(int node) { - for (int v : edge[node]) { - findNext(v); - if (nxt[node] == -1 || nxt[node] > min(v, nxt[v])) { - nxt[node] = min(v, nxt[v]); - } - } - - // 叶子节点 - if (nxt[node] == -1) { - nxt[node] = node; - } -} - -// 计算从节点u出发经过若干次传送门到达叶子节点所需的步数。 -// 通过不断访问nxt节点,直到到达叶子节点,记录访问的节点数。 -int get(int u) { - int cnt = 1; - while (nxt[u] != u) { - cnt++; - u = nxt[u]; - } - return cnt; -} - -int main() { - cin >> n; - edge.resize(n + 1); - nxt.resize(n + 1, -1); - for (int i = 1; i <= n; ++i) { - int a, b; - cin >> a >> b; - edge[a].push_back(b); - } - findNext(1); - for (int i = 1; i <= n; ++i) { - cout << get(i) << ' '; - } -} - -``` diff --git a/problems/kamacoder/0147.三珠互斥.md b/problems/kamacoder/0147.三珠互斥.md deleted file mode 100644 index 2ef5d392..00000000 --- a/problems/kamacoder/0147.三珠互斥.md +++ /dev/null @@ -1,78 +0,0 @@ - -# 三珠互斥 - -1. 如果k * 3 大于 n 了,那说明一定没结果,如果没想明白,大家举个例子试试看 -2. 分别求出三个红珠子之间的距离 -3. 对这三段距离从小到大排序 y1, y2, y3 -4. 如果第一段距离y1 小于k,说明需要交换 k - y 次, 同理 第二段距离y2 小于k,说明需要交换 k - y2 次 -5. y1 y2 都调整好了,不用计算y3,因为 y3是距离最大 - -```CPP -#include -using namespace std; - -int main(){ - int t; - cin >> t; - int n, k, a1, a2, a3; - vector dis(3); - - while (t--) { - cin >> n >> k >> a1 >> a2 >> a3; - if(k * 3 > n){ - cout << -1 << endl; - continue; - } - dis[0] = min(abs(a1 - a2), n - abs(a1 - a2)); - dis[1] = min(abs(a1 - a3), n - abs(a1 - a3)); - dis[2] = min(abs(a3 - a2), n - abs(a3 - a2)); - - sort(dis.begin(), dis.end()); - - int result = 0; - if (dis[0] < k) result += (k - dis[0]); - if (dis[1] < k) result += (k - dis[1]); - - cout << result << endl; - } - return 0; -} -``` - -Java代码: - -```Java -import java.util.*; - -public class Main { - public static void main(String[] args) { - Scanner scanner = new Scanner(System.in); - int t = scanner.nextInt(); - - while (t-- > 0) { - int n = scanner.nextInt(); - int k = scanner.nextInt(); - int a1 = scanner.nextInt(); - int a2 = scanner.nextInt(); - int a3 = scanner.nextInt(); - if (k * 3 > n) { - System.out.println(-1); - continue; - } - - List dis = new ArrayList<>(3); - dis.add(Math.min(Math.abs(a1 - a2), n - Math.abs(a1 - a2))); - dis.add(Math.min(Math.abs(a1 - a3), n - Math.abs(a1 - a3))); - dis.add(Math.min(Math.abs(a3 - a2), n - Math.abs(a3 - a2))); - - Collections.sort(dis); - - int result = 0; - if (dis.get(0) < k) result += (k - dis.get(0)); - if (dis.get(1) < k) result += (k - dis.get(1)); - - System.out.println(result); - } - } -} -``` diff --git a/problems/kamacoder/0148.扑克牌同花顺.md b/problems/kamacoder/0148.扑克牌同花顺.md deleted file mode 100644 index cf8d325f..00000000 --- a/problems/kamacoder/0148.扑克牌同花顺.md +++ /dev/null @@ -1,122 +0,0 @@ - -# 扑克牌同花顺 - -首先我们要定义一个结构体,来存放我们的数据 - -`map<花色,{同一花色牌集合,同一花色的牌对应的牌数量}>` - -再遍历 每一个花色下,每一个牌 的数量 - -代码如下详细注释: - - -```CPP -#include -using namespace std; - -string cards[] = {"H","S","D","C"}; -typedef long long ll; -struct color -{ - set st; // 同一花色 牌的集合 - map cnt; // 同一花色 牌对应的数量 -}; -unordered_map umap; - -int main() { - int n; - cin >> n; - for (int i = 0; i < n; i++) { - int x, y; - string card; - cin >> x >> y >> card; - umap[card].st.insert(x); - umap[card].cnt[x] += y; - } - ll sum = 0; - // 遍历每一个花色 - for (string cardOne : cards) { - color colorOne = umap[cardOne]; - // 遍历 同花色 每一个牌 - for (int number : colorOne.st) { - ll numberCount = colorOne.cnt[number]; // 获取牌为number的数量是 numberCount - - // 统计 number 到 number + 4 都是否有牌,用cal 把 number 到number+4 的数量记下来 - ll cal = numberCount; - for (int j = number + 1; j <= number + 4; j++) cal = min(cal, colorOne.cnt[j]); - // 统计结果 - sum += cal; - // 把统计过的同花顺数量减下去 - for (int j = number + 1; j <= number + 4; j++) colorOne.cnt[j] -= cal; - } - } - cout << sum << endl; -} -``` - -Java代码如下: - -```Java - -import java.util.*; - -public class Main { - static String[] cards = {"H", "S", "D", "C"}; // 花色数组 - - static class Color { - Set st; // 同一花色牌的集合 - Map cnt; // 同一花色牌对应的数量 - - Color() { - st = new HashSet<>(); // 初始化集合 - cnt = new HashMap<>(); // 初始化映射 - } - } - - static Map umap = new HashMap<>(); // 用于存储每种花色对应的Color对象 - - public static void main(String[] args) { - Scanner scanner = new Scanner(System.in); - int n = scanner.nextInt(); // 读取牌的数量 - - for (int i = 0; i < n; i++) { - int x = scanner.nextInt(); // 读取牌的值 - int y = scanner.nextInt(); // 读取牌的数量 - String card = scanner.next(); // 读取牌的花色 - - umap.putIfAbsent(card, new Color()); // 如果不存在该花色,则创建一个新的Color对象 - umap.get(card).st.add(x); // 将牌的值加入集合 - umap.get(card).cnt.put(x, umap.get(card).cnt.getOrDefault(x, 0L) + y); // 更新牌的数量 - } - - long sum = 0; // 结果累加器 - - // 遍历每一种花色 - for (String cardOne : cards) { - Color colorOne = umap.getOrDefault(cardOne, new Color()); // 获取对应花色的Color对象 - - // 遍历同花色的每一张牌 - for (int number : colorOne.st) { - long numberCount = colorOne.cnt.get(number); // 获取当前牌的数量 - - // 计算从当前牌到number+4的最小数量 - long cal = numberCount; - for (int j = number + 1; j <= number + 4; j++) { - cal = Math.min(cal, colorOne.cnt.getOrDefault(j, 0L)); // 更新cal为最小值 - } - - // 将结果累加到sum - sum += cal; - - // 将统计过的同花顺数量减去 - for (int j = number + 1; j <= number + 4; j++) { - colorOne.cnt.put(j, colorOne.cnt.getOrDefault(j, 0L) - cal); - } - } - } - - System.out.println(sum); // 输出结果 - } -} - -``` diff --git a/problems/kamacoder/0149.好数组.md b/problems/kamacoder/0149.好数组.md deleted file mode 100644 index 09088168..00000000 --- a/problems/kamacoder/0149.好数组.md +++ /dev/null @@ -1,102 +0,0 @@ - -# 149. 好数组 - -贪心思路: - -整体思路是移动到中间位置(中位数),一定是 移动次数最小的。 - -有一个数可以不改变,对数组排序之后, 最小数 和 最大数 一定是移动次数最多的,所以分别保留最小 和 最大的不变。 - -中间可能有两个位置,所以要计算中间偏前 和 中间偏后的 - -代码如下: - -```CPP -#include -using namespace std; - -int main() { - int n; - cin >> n; - vector arr(n); - for (int i = 0; i < n; ++i) { - cin >> arr[i]; - } - sort(arr.begin(), arr.end()); - - if (arr[0] == arr[n - 1]) { - cout << 1 << endl; - return 0; - } - long cnt = 0L; - long cnt1 = 0L; - - // 如果要保留一个不改变,要不不改最小的,要不不改最大的。 - - // 取中间偏前的位置 - long mid = arr[(n - 2) / 2]; - - // 不改最大的 - for (int i = 0; i < n - 1; i++) { - cnt += abs(arr[i] - mid); - } - - // 取中间偏后的位置 - mid = arr[n / 2]; - - // 不改最小的 - for (int i = 1; i < n; i++) { - cnt1 += abs(arr[i] - mid); - } - - cout << min(cnt, cnt1) << endl; - return 0; -} -``` - -Java代码如下: - -```Java - -import java.util.*; - -public class Main { - public static void main(String[] args) { - Scanner scanner = new Scanner(System.in); - int n = scanner.nextInt(); - long[] arr = new long[n]; - for (int i = 0; i < n; ++i) { - arr[i] = scanner.nextLong(); - } - Arrays.sort(arr); - - if (arr[0] == arr[n - 1]) { - System.out.println(1); - return; - } - long cnt = 0L; - long cnt1 = 0L; - - // 如果要保留一个不改变,要不不改最小的,要不不改最大的。 - - // 取中间偏前的位置 - long mid = arr[(n - 2) / 2]; - - // 不改最大的 - for (int i = 0; i < n - 1; i++) { - cnt += Math.abs(arr[i] - mid); - } - - // 取中间偏后的位置 - mid = arr[n / 2]; - - // 不改最小的 - for (int i = 1; i < n; i++) { - cnt1 += Math.abs(arr[i] - mid); - } - - System.out.println(Math.min(cnt, cnt1)); - } -} - -``` diff --git a/problems/kamacoder/0150.极长连续段的权值.md b/problems/kamacoder/0150.极长连续段的权值.md deleted file mode 100644 index 503d6a23..00000000 --- a/problems/kamacoder/0150.极长连续段的权值.md +++ /dev/null @@ -1,66 +0,0 @@ - -# 150. 极长连续段的权值 - -动态规划,枚举最后边节点的情况: - -```CPP -#include -#include -using namespace std; - -int main() { - int n; - cin >> n; - string s; - cin >> s; - - long long result = 1; - long long a = 1; - - for (int i = 1; i < n; ++i) { - // 加上本身长度为1的子串 - if (s[i] == s[i - 1]) { - a += 1; - result += a; - // 以最右节点为终点,每个子串的级长连续段都+1,再加本身长度为1的子串 - } else { - a = a + i + 1; - result += a; - } - } - cout << result << endl; - return 0; -} -``` - -Java代码如下: - -```Java -import java.util.Scanner; - -public class Main { - public static void main(String[] args) { - Scanner scanner = new Scanner(System.in); - int n = scanner.nextInt(); - String s = scanner.next(); - - long result = 1; - long a = 1; - - for (int i = 1; i < n; ++i) { - // 加上本身长度为1的子串 - if (s.charAt(i) == s.charAt(i - 1)) { - a += 1; - result += a; - // 以最右节点为终点,每个子串的级长连续段都+1,再加本身长度为1的子串 - } else { - a = a + i + 1; - result += a; - } - } - - System.out.println(result); - } -} - -``` diff --git a/problems/kamacoder/0151.手机流畅运行的秘密.md b/problems/kamacoder/0151.手机流畅运行的秘密.md deleted file mode 100644 index 3859f7b0..00000000 --- a/problems/kamacoder/0151.手机流畅运行的秘密.md +++ /dev/null @@ -1,127 +0,0 @@ -# 151. 手机流畅运行的秘密 - -[题目链接](https://kamacoder.com/problempage.php?pid=1229) - -先运行 能留下电量多的 任务,才能有余电运行其他任务。 - -任务1,1:10 ,运行完 能留下 9个电 - -任务2,2:12,运行完 能留下 10个电 - -任务3,3:10,运行完 能留下 7个电。 - -运行顺序: 任务2 -> 任务1 -> 任务3 - -按照 最低初始电量 - 耗电量,从大到小排序。 - -计算总电量,需要 从小到大 遍历, 不断取 总电量 + 任务耗电量 与 任务最低初始电量 的最大值。 - -```CPP -#include -using namespace std; - -bool cmp(const pair& taskA, const pair& taskB) { - return (taskA.second - taskA.first) < (taskB.second - taskB.first); -} -int main() { - string str, tmp; - vector> tasks; - - //处理输入 - getline(cin, str); - stringstream ss(str); - while (getline(ss, tmp, ',')) { - int p = tmp.find(":"); - string a = tmp.substr(0, p); - string b = tmp.substr(p + 1); - tasks.push_back({stoi(a), stoi(b)}); - } - - // 按照差值从小到大排序 - sort(tasks.begin(), tasks.end(), cmp); - - // 收集结果 - int result = 0; - for (int i = 0 ; i < tasks.size(); i++) { - result = max(result + tasks[i].first, tasks[i].second); - } - - result = result <= 4800 ? result : -1; - cout << result << endl; - -} -``` - -Java版本: - -```Java -import java.util.*; -import java.util.stream.Collectors; - -public class Main { - public static void main(String[] args) { - Scanner sc = new Scanner(System.in); - String str = sc.nextLine(); - String[] tasksArray = str.split(","); - List tasks = Arrays.stream(tasksArray) - .map(task -> { - String[] parts = task.split(":"); - return new Pair(Integer.parseInt(parts[0]), Integer.parseInt(parts[1])); - }) - .collect(Collectors.toList()); - - // 按照差值从小到大排序 - Collections.sort(tasks, (taskA, taskB) -> - (taskA.second - taskA.first) - (taskB.second - taskB.first) - ); - - // 收集结果 - int result = 0; - for (Pair task : tasks) { - result = Math.max(result + task.first, task.second); - } - - result = result <= 4800 ? result : -1; - System.out.println(result); - } -} - -class Pair { - int first; - int second; - - Pair(int first, int second) { - this.first = first; - this.second = second; - } -} - -``` - -Python版本: - -```python -def main(): - import sys - input = sys.stdin.read - - str = input().strip() - tasks = [] - for tmp in str.split(','): - a, b = map(int, tmp.split(':')) - tasks.append((a, b)) - - # 按照差值从小到大排序 - tasks.sort(key=lambda task: task[1] - task[0]) - - # 收集结果 - result = 0 - for task in tasks: - result = max(result + task[0], task[1]) - - result = result if result <= 4800 else -1 - print(result) - -if __name__ == "__main__": - main() -``` diff --git a/problems/kamacoder/0152.小米手机通信校准.md b/problems/kamacoder/0152.小米手机通信校准.md deleted file mode 100644 index afb5d8ea..00000000 --- a/problems/kamacoder/0152.小米手机通信校准.md +++ /dev/null @@ -1,121 +0,0 @@ - - -# 152. 小米手机通信校准 - -[题目链接](https://kamacoder.com/problempage.php?pid=1230) - -一道模拟题,但比较考察 代码能力。 - -遍历去找 里 freq 最近的 freg就好, 需要记录刚遍历过的的freg和 loss,因为可能有 相邻一样的 freg。 - -```CPP -#include -using namespace std; - -int main() { - int freq; - cin >> freq; - string data; - double result = 0; - int last_freg = 0; // 记录上一个 freg - int last_loss = 0; // 记录上一个loss - while(cin >> data) { - int index = data.find(':'); - int freg = stoi(data.substr(0, index)); // 获取 freg 和 loss - int loss = stoi(data.substr(index + 1)); - // 两遍一样 - if(abs(freg - freq) == abs(last_freg - freq)) { - result = (double)(last_loss + loss)/2.0; - } // 否则更新最新的result - else if(abs(freg - freq) < abs(last_freg - freq)){ - result = (double)loss; - } - last_freg = freg; - last_loss = loss; - } - printf("%.1lf\n", result); - return 0; -} - -``` - -Java 版本: - -```Java - -import java.util.Scanner; - -public class Main { - public static void main(String[] args) { - Scanner sc = new Scanner(System.in); - int freq = sc.nextInt(); - sc.nextLine(); // 读取换行符 - - String inputLine = sc.nextLine(); // 读取包含所有后续输入的行 - String[] data = inputLine.split(" "); // 根据空格分割输入 - - double result = 0; - int lastFreq = 0; // 记录上一个 freg - int lastLoss = 0; // 记录上一个 loss - - for (String entry : data) { - int index = entry.indexOf(':'); - int freg = Integer.parseInt(entry.substring(0, index)); // 获取 freg 和 loss - int loss = Integer.parseInt(entry.substring(index + 1)); - - // 两遍一样 - if (Math.abs(freg - freq) == Math.abs(lastFreq - freq)) { - result = (double) (lastLoss + loss) / 2.0; - } - // 否则更新最新的 result - else if (Math.abs(freg - freq) < Math.abs(lastFreq - freq)) { - result = (double) loss; - } - - lastFreq = freg; - lastLoss = loss; - } - - System.out.printf("%.1f\n", result); - sc.close(); - } -} - -``` - -Python版本: - -```python -def main(): - import sys - input = sys.stdin.read - data = input().split() - - freq = int(data[0]) - result = 0 - last_freg = 0 # 记录上一个 freg - last_loss = 0 # 记录上一个 loss - - for i in range(1, len(data)): - item = data[i] - index = item.find(':') - freg = int(item[:index]) # 获取 freg 和 loss - loss = int(item[index + 1:]) - - # 两遍一样 - if abs(freg - freq) == abs(last_freg - freq): - result = (last_loss + loss) / 2.0 - # 否则更新最新的 result - elif abs(freg - freq) < abs(last_freg - freq): - result = loss - - last_freg = freg - last_loss = loss - - print(f"{result:.1f}") - -if __name__ == "__main__": - main() - - -``` diff --git a/problems/kamacoder/0153.权值优势路径计数.md b/problems/kamacoder/0153.权值优势路径计数.md deleted file mode 100644 index 2c5562b3..00000000 --- a/problems/kamacoder/0153.权值优势路径计数.md +++ /dev/null @@ -1,95 +0,0 @@ - - -# 权值优势路径计数 - -[题目链接](https://kamacoder.com/problempage.php?pid=1231) - -1、构建二叉树:首先根据层序遍历的序列构建二叉树。这可以通过使用队列来实现,队列中存储当前节点及其索引,确保可以正确地将子节点添加到父节点下。 - -2、路径遍历:使用深度优先搜索(DFS)遍历所有从根到叶子的路径。在遍历过程中,维护一个计数器跟踪当前路径中权值为 1 和权值为 0 的节点的数量。 - -3、计数满足条件的路径:每当到达一个叶子节点时,检查当前路径的权值 1 的节点数量是否比权值 0 的节点数量多 1。如果满足,递增一个全局计数器。 - - -```CPP - -#include -#include -#include - -using namespace std; - -struct TreeNode { - int val; - TreeNode *left, *right; - TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} -}; - -// DFS遍历二叉树,并计算满足条件的路径数量 -void countPaths(TreeNode* node, int count1, int count0, int& result) { - if (!node) return; - - // 更新当前路径中1和0的数量 - node->val == 1 ? count1++ : count0++; - - // 检查当前节点是否为叶子节点 - if (!node->left && !node->right) { - // 检查1的数量是否比0的数量多1 - if (count1 == count0 + 1) { - result++; - } - return; - } - - // 递归访问左右子节点 - countPaths(node->left, count1, count0, result); - countPaths(node->right, count1, count0, result); -} - -int main() { - int N; - cin >> N; - - vector nums(N); - for (int i = 0; i < N; ++i) { - cin >> nums[i]; - } - - if (nums.empty()) { - cout << 0 << endl; - return 0; - } - - // 根据层序遍历的输入构建二叉树 - queue q; - TreeNode* root = new TreeNode(nums[0]); - q.push(root); - int index = 1; - - while (!q.empty() && index < N) { - TreeNode* node = q.front(); - q.pop(); - - if (index < N && nums[index] != -1) { - node->left = new TreeNode(nums[index]); - q.push(node->left); - } - index++; - - if (index < N && nums[index] != -1) { - node->right = new TreeNode(nums[index]); - q.push(node->right); - } - index++; - } - - // 计算满足条件的路径数 - int result = 0; - countPaths(root, 0, 0, result); - - cout << result << endl; - - return 0; -} - -``` diff --git a/problems/kamacoder/0154.序列中位数.md b/problems/kamacoder/0154.序列中位数.md deleted file mode 100644 index 90e5b7a4..00000000 --- a/problems/kamacoder/0154.序列中位数.md +++ /dev/null @@ -1,68 +0,0 @@ - -# 序列中位数 - -[题目链接](https://kamacoder.com/problempage.php?pid=1232) - -注意给的数组默认不是有序的! - -模拟题,排序之后,取中位数,然后按照b数组 删 a数组中元素,再取中位数。 - -```CPP -#include -using namespace std; - -// 计算并返回中位数 -double findMedian(vector& nums) { - int n = nums.size(); - if (n % 2 == 1) { - return nums[n / 2]; // 奇数长度,返回中间的元素 - } else { - // 偶数长度,返回中间两个元素的平均值 - return (nums[n / 2] + nums[n / 2 - 1]) / 2.0; - } -} - - -int main(){ - int t; - cin >> t; - while(t--){ - int n; - cin>> n; - vector a(n); - vector b(n - 1); - for(int i = 0; i < n; i++){ - cin >> a[i]; - } - for(int i = 0; i < n - 1; i++){ - cin >> b[i]; - } - vector nums = a; - vector answers; - - sort(nums.begin(), nums.end()); - - // 把中位数放进结果集 - answers.push_back(findMedian(nums)); - - for(int i = 0; i < n - 1; i++){ - - int target = a[b[i]]; - // 删除目标值 - nums.erase(find(nums.begin(), nums.end(), target)); - // 把中位数放进结果集 - answers.push_back(findMedian(nums)); - - } - - for(auto answer : answers){ - // 判断是否是整数 - if(answer == (int)answer) printf("%d ", (int)answer); - else printf("%.1f ", answer); - } - cout << endl; - } - -} - -``` diff --git a/problems/kamacoder/0155.最小化频率的删除代价.md b/problems/kamacoder/0155.最小化频率的删除代价.md deleted file mode 100644 index d79d6955..00000000 --- a/problems/kamacoder/0155.最小化频率的删除代价.md +++ /dev/null @@ -1,106 +0,0 @@ - -# 最小化频率的删除代价 - -[题目链接](https://kamacoder.com/problempage.php?pid=1233) - -计数和排序: - -* 使用 map 或 unordered_map 对数组 a 中每个元素出现的次数进行统计。 -* 将统计结果存入一个 vector>,其中 pair 的第一个元素是元素的出现次数,第二个元素是元素本身。 -* 按出现次数从大到小排序这个 vector。 - -确定最小 f(a): - -* 从最大出现次数开始尝试减少 f(a)。为此,从最高频次的元素开始逐步向下考虑较少出现的元素,计算达到更低 f(a) 所需删除的元素数量。 -* 使用一个累加器 count 来记录需要删除的元素数量,直到这个数量超过允许的最大删除数量 k 或恰好等于 k。在此过程中,尽量使 f(a) 达到最小。 - -计算达到 f(a) 的代价: - -* 计算完成后,需要确定达到最小 f(a) 的确切代价。首先,为每个元素确定在不超过 k 的前提下可以删除的最大数量,以使得 f(a) 最小。 -* 对于每个元素,如果它的数量超过了新的 f(a),则计算减少到 f(a) 所需删除的具体元素数,记录下来。 - -计算具体删除代价: - -* 遍历原数组,对于每个需要删除的元素,根据其位置累加删除代价。每删除一个元素,相应地减少其在删除列表中的计数。当某元素需要删除的数量减至 0 时,从删除列表中移除该元素。 - - -```CPP - -#include -#include -#include -#include - -using namespace std; - -int main() { - int n, k; - cin >> n >> k; - - vector a(n); - for (int i = 0; i < n; ++i) { - cin >> a[i]; - } - - unordered_map umap; // 使用map来统计每个元素的出现频率 - for (int i = 0; i < n; ++i) { - umap[a[i]]++; // 统计每个元素的出现次数 - } - - vector> table; - for (auto& pair : umap) { - table.push_back({pair.second, pair.first}); // 将元素和其频率作为一个pair放入table中 - } - - sort(table.begin(), table.end(), greater<>()); // 将table按照频率从大到小排序 - - int count = 0; // 用来计算已经删除的元素总数 - int minVal = table[0].first; // 从最高频率开始 - for (int i = 0; i < table.size(); ++i) { - int freq = table[i].first; - count += (minVal - freq) * i; // 累加删除元素的代价 - if (count > k) break; // 如果超过了k,停止循环 - else if (count == k) { - minVal = freq; - break; - } else minVal = freq; - } - if (count < k) { - int addDel = (k - count) / table.size(); // 如果删除的代价还没达到k,计算还可以进一步减少的频率 - minVal -= addDel; // 减少相应的频率 - } - - if (minVal < 0) { - minVal = 0; // 确保最小频率值不小于0 - } - - unordered_map deleteList; // 用来存储需要删除的元素及其数量 - for (auto& elem : table) { - int num = elem.first; - int ind = elem.second; - if (num > minVal) { - deleteList[ind] = num - minVal; // 如果元素频率大于最小值,计算需要删除的数量 - } else { - break; - } - } - - int cost = 0; // 计算总的删除代价 - for (int i = 0; i < n; ++i) { - if (deleteList.find(a[i]) != deleteList.end()) { - cost += i + 1; // 删除的代价是元素的索引+1 - deleteList[a[i]]--; // 删除一个元素 - if (deleteList[a[i]] == 0) { - deleteList.erase(a[i]); // 如果元素已经全部删除,从列表中移除 - if (deleteList.empty()) { - break; // 如果没有元素需要删除了,结束循环 - } - } - } - } - - cout << minVal << " " << cost << endl; - return 0; -} - -``` diff --git a/problems/kamacoder/0156.勇敢牛牛战斗序列.md b/problems/kamacoder/0156.勇敢牛牛战斗序列.md deleted file mode 100644 index b7bea974..00000000 --- a/problems/kamacoder/0156.勇敢牛牛战斗序列.md +++ /dev/null @@ -1,68 +0,0 @@ - -# 勇敢牛牛战斗序列 - -[题目链接](https://kamacoder.com/problempage.php?pid=1234) - -贪心思路,对数组从小到大排序之后,先取最右边,再取最左边,循环反复。 - -```CPP -#include - -using namespace std; - -int main() { - int n; - cin >> n; - vector a(n); // 使用 vector 存储整数数组 - for (int i = 0; i < n; i++) { - cin >> a[i]; // 读取数组 - } - sort(a.begin(), a.end()); // 对数组进行排序 - - long long ans = 0; // 使用 long long 存储结果,以防溢出 - int cur = 0; - int left = 0, right = n - 1; - while (left <= right) { - if (cur < a[right]) { - ans += a[right] - cur; - } - cur = a[left]; - right--; - left++; - } - cout << ans << endl; // 输出结果 - return 0; -} -``` - - - -```Java -import java.util.Arrays; -import java.util.Scanner; - -public class Main { - - public static void main(String[] args) { - Scanner sc = new Scanner(System.in); - int n = sc.nextInt(); - int[] a = new int[n]; - for (int i = 0; i < n; i++) { - a[i] = sc.nextInt(); - } - Arrays.sort(a); - long ans = 0; - int cur = 0; - int left = 0, right = a.length - 1; - while (left <= right) { - if (cur < a[right]) { - ans = ans + a[right] - cur; - } - cur = a[left]; - right--; - left++; - } - System.out.println(ans); - } -} -``` diff --git a/problems/kamacoder/0157.最大化密码复杂度.md b/problems/kamacoder/0157.最大化密码复杂度.md deleted file mode 100644 index 9ca4630d..00000000 --- a/problems/kamacoder/0157.最大化密码复杂度.md +++ /dev/null @@ -1,59 +0,0 @@ - -# 最大化密码复杂度 - -[题目链接](https://kamacoder.com/problempage.php?pid=1235) - -注意**边界处理**,对于字符串的首尾位置,需要特别处理,因为它们只有一个相邻字符。 -* 遍历字符串 s,寻找 '?' 字符。 -* 对于每个 '?' 字符,选择一个字符填充,使其与前后字符都不同。这样做的目的是最大化密码的复杂度,即尽可能使相邻的字符不同。 -* 如果 '?' 是第一个或最后一个字符,或者无法找到与前后都不同的字符,选择与前一个或后一个字符不同的字符。 - - -```CPP -#include -#include -#include - -using namespace std; - -int main() { - int n, m; - string s; - cin >> n >> m >> s; - - if (n == 1) { - cout << 0 << endl; - return 0; - } - - // 统一处理包括左右字符的情况 - for (int i = 0; i < n; ++i) { - if (s[i] == '?') { - bool found = false; - for (char j = 'a'; j < 'a' + m; ++j) { - // 避免第一个字符 和 最后一个字符,因为两个字符只有一个相邻字符,没有左右相邻字符 - if ((i == 0 || s[i - 1] != j) && (i == n - 1 || s[i + 1] != j)) { - s[i] = j; - found = true; - break; - } - } - // 如果没有找到合适的字符,就和附近字符保持一致 - if (!found) { - if (i > 0) s[i] = s[i - 1]; - else s[i] = s[i + 1]; - } - } - } - - // 计算结果 - int result = 0; - for (int i = 0; i < n - 1; ++i) { - if (s[i] != s[i + 1]) result++; - } - - cout << result << endl; - return 0; -} - -``` diff --git a/problems/kamacoder/0158.同余方程.md b/problems/kamacoder/0158.同余方程.md deleted file mode 100644 index b99481d2..00000000 --- a/problems/kamacoder/0158.同余方程.md +++ /dev/null @@ -1,50 +0,0 @@ - -# 同余方程 - -题目链接:https://kamacoder.com/problempage.php?pid=1236 - -我们需要求出满足以下条件的最小正整数 x:`ax≡1 (mod b)` - -这意味着我们需要找到 x 使得 ax 除以 b 的余数是 1。这个问题实际上是一个典型的 模反元素 问题。 - -解题思路: - -* 为了求出最小的 x,我们可以使用 扩展欧几里得算法 来求出 a 对模 b 的逆元。 -* 这个算法能够求解 ax + by = gcd(a, b) 的一组整数解 (x, y),而在 gcd(a, b) = 1 的情况下,x 即为所求的模逆元。 -* 扩展欧几里得算法:扩展欧几里得算法可以通过递归或者迭代的方式实现。 - -下面给出C++代码实现: - -```CPP -#include -using namespace std; - -// 扩展欧几里得:计算 ax + by = gcd(a, b) 的解 -long long extended_gcd(long long a, long long b, long long &x, long long &y) { - if (b == 0) { - x = 1; - y = 0; - return a; - } - long long x1, y1; - long long gcd = extended_gcd(b, a % b, x1, y1); - x = y1; - y = x1 - (a / b) * y1; - return gcd; -} - -int main() { - long long a, b; - cin >> a >> b; - - long long x, y; - long long gcd = extended_gcd(a, b, x, y); - - // 由于我们只需要模 b 的正整数解,所以我们要保证 x 是正数 - x = (x % b + b) % b; - - cout << x << endl; - - return 0; -} -``` diff --git a/problems/kamacoder/0159.大整数乘法.md b/problems/kamacoder/0159.大整数乘法.md deleted file mode 100644 index 642cb746..00000000 --- a/problems/kamacoder/0159.大整数乘法.md +++ /dev/null @@ -1,62 +0,0 @@ - -# 大整数乘法 - -题目链接:https://kamacoder.com/problempage.php?pid=1237 - -思路: - -我们可以使用模拟手算乘法的方法,即「逐位相乘累加」,对于每一位的乘法结果,我们将其加到相应的结果位置上。最终将累加的结果输出。 - -具体步骤: - -* 初始化结果数组:结果数组的长度应该是两个数字长度之和,因为最大长度的结果不会超过这个长度。 -* 逐位相乘:从右往左遍历两个字符串的每一位,逐位相乘,并加到结果数组的相应位置。 -* 处理进位:在每一步累加之后处理进位,保证每个位置的值小于10。 - -将结果数组转化为字符串:从结果数组的最高位开始,忽略前导零,然后将数组转化为字符串。 - -```CPP -#include -#include -#include - -using namespace std; - -string multiply(string num1, string num2) { - int len1 = num1.size(); - int len2 = num2.size(); - vector result(len1 + len2, 0); - - // 逐位相乘 - for (int i = len1 - 1; i >= 0; i--) { - for (int j = len2 - 1; j >= 0; j--) { - int mul = (num1[i] - '0') * (num2[j] - '0'); - int sum = mul + result[i + j + 1]; - - result[i + j + 1] = sum % 10; - result[i + j] += sum / 10; - } - } - - // 将结果转换为字符串,跳过前导零 - string product; - for (int num : result) { - if (!(product.empty() && num == 0)) { // 跳过前导零 - product.push_back(num + '0'); - } - } - - return product.empty() ? "0" : product; -} - -int main() { - string num1, num2; - cin >> num1 >> num2; - - string result = multiply(num1, num2); - cout << result << endl; - - return 0; -} - -``` diff --git a/problems/kamacoder/0160.二维平面上的折线段.md b/problems/kamacoder/0160.二维平面上的折线段.md deleted file mode 100644 index 35c3ea32..00000000 --- a/problems/kamacoder/0160.二维平面上的折线段.md +++ /dev/null @@ -1,88 +0,0 @@ - -# 二维平面上的折线段 - -题目链接:https://kamacoder.com/problempage.php?pid=1238 - -这个问题要求我们在一条折线段上,根据移动的固定距离 s 进行标记点的计算。 - -为了实现这一点,我们需要对折线段进行分段处理,并根据每段的长度来确定标记点的位置。 - -解题思路: - -1. 输入与初步处理: - * 首先,读取所有点的坐标。 - * 计算每一段折线的长度,并逐段累积总长度。 -2. 确定标记点: - * 从起点开始,每次沿着折线段前进 s 的距离,直到到达终点。 - * 对于每个标记点,根据当前段的起点和终点,计算出该点的精确坐标。 -3. 输出所有标记点的坐标,格式为 x, y。 - -```CPP - -#include -#include -#include -#include - -using namespace std; - -// 定义一个点的结构体 -struct Point { - double x, y; -}; - -// 计算两点之间的距离 -double distance(const Point& a, const Point& b) { - return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y)); -} - -int main() { - int n; - cin >> n; - - vector points(n); - for (int i = 0; i < n; i++) { - cin >> points[i].x >> points[i].y; - } - - double s; - cin >> s; - - double total_length = 0.0; - vector segment_lengths(n - 1); - - // 计算每段长度和总长度 - for (int i = 0; i < n - 1; i++) { - segment_lengths[i] = distance(points[i], points[i + 1]); - total_length += segment_lengths[i]; - } - - // 从起点开始标记 - Point current_point = points[0]; - double accumulated_distance = 0.0; - - cout << fixed << setprecision(5); - cout << current_point.x << ", " << current_point.y << endl; - - while (accumulated_distance + s <= total_length) { - accumulated_distance += s; - double remaining_distance = accumulated_distance; - - for (int i = 0; i < n - 1; i++) { - if (remaining_distance <= segment_lengths[i]) { - double ratio = remaining_distance / segment_lengths[i]; - double new_x = points[i].x + ratio * (points[i + 1].x - points[i].x); - double new_y = points[i].y + ratio * (points[i + 1].y - points[i].y); - current_point = {new_x, new_y}; - cout << current_point.x << ", " << current_point.y << endl; - break; - } else { - remaining_distance -= segment_lengths[i]; - } - } - } - - return 0; -} - -``` diff --git a/problems/kamacoder/0161.讨厌鬼的组合帖子.md b/problems/kamacoder/0161.讨厌鬼的组合帖子.md deleted file mode 100644 index 84471f8c..00000000 --- a/problems/kamacoder/0161.讨厌鬼的组合帖子.md +++ /dev/null @@ -1,61 +0,0 @@ - -# 讨厌鬼的组合帖子 - -[题目链接](https://kamacoder.com/problempage.php?pid=1239) - -这个问题本质上是要找到两个数组的子集,使得这两个子集之间的差的绝对值最大。 - -问题可以简化为寻找两个数列之间最大可能的差的绝对值。 - -贪心思路如下: - -计算差异,首先,我们可以计算每个帖子的点赞数和点踩数的差值 d[i] = a[i] - b[i]。这样问题就转化为选择这些差值的一个子集,使得子集中所有元素的和的绝对值最大。 - -遍历可能性,要使得一个数的绝对值尽可能大,可以尝试最大化这个数,或者最小化这个数(使其尽可能小于零)。我们可以分别尝试将所有正的差值加在一起,以及将所有负的差值加在一起。 - -计算最大吸引度: - -* 将所有正的差值求和得到一个总和。 -* 将所有负的差值求和得到另一个总和。 -* 最后,吸引度即为这两个总和的绝对值中的较大者。 - - -```CPP - -#include -#include -#include - -using namespace std; - -int main() { - int n; - cin >> n; - - vector a(n), b(n); - for (int i = 0; i < n; ++i) { - cin >> a[i]; - } - for (int i = 0; i < n; ++i) { - cin >> b[i]; - } - - long long positive_sum = 0; - long long negative_sum = 0; - - for (int i = 0; i < n; ++i) { - int difference = a[i] - b[i]; - if (difference > 0) { - positive_sum += difference; - } else if (difference < 0) { - negative_sum += difference; - } - } - - // 最大吸引度是正总和或负总和的绝对值中的较大者 - cout << max(abs(positive_sum), abs(negative_sum)) << endl; - - return 0; -} -``` - diff --git a/problems/kamacoder/0163.优秀数组.md b/problems/kamacoder/0163.优秀数组.md deleted file mode 100644 index 4967f907..00000000 --- a/problems/kamacoder/0163.优秀数组.md +++ /dev/null @@ -1,88 +0,0 @@ - -# 优秀数组 - -[题目链接](https://kamacoder.com/problempage.php?pid=1241) - -## 解题思路 - -1、初始分析 - -- 给定一个排列 `p`,我们首先构建一个 `pos` 数组,使得 `pos[i]` 表示 `i` 在排列 `p` 中的位置。 -- 我们需要判断数组 `a` 是否是一个优秀数组,即 `pos[a[i]] < pos[a[i+1]] <= pos[a[i]] + d` 对于所有 `i` 都成立。 -- 我们的目标是通过最少的相邻元素交换,使得数组 `a` 不再是一个优秀数组。 - -2、思路 - -- 要使数组 `a` 不再是优秀数组,我们只需要打破条件 `pos[a[i]] < pos[a[i+1]] <= pos[a[i]] + d` 中的某一个。 -- 一种简单的做法是让 `pos[a[i]]` 和 `pos[a[i+1]]` 之间的距离超过 `d`,或者直接让 `pos[a[i]] >= pos[a[i+1]]`。 - -3、具体方法 - -- 只需要考虑 `a` 中相邻元素的顺序,并判断如何交换 `p` 中相邻元素使得其顺序被打破。 -- 假设我们需要在 `p` 中交换某些元素来实现上述目标,那么最小的交换次数是将 `a[i]` 和 `a[i+1]` 的位置交换。 -- 如果 `pos[a[i]] + 1 == pos[a[i+1]]`,则需要一步交换。 - -4、特别情况 - -- 还需要考虑,如果通过交换相邻元素无法解决问题的情况。比如 `pos[a[i+1]]` 的位置无法移到 `pos[a[i]]` 的前面或超过 `d`。 - -C++代码如下: - - -```cpp -#include -#include -#include -#include - -using namespace std; - -int main() { - int n, m, d; - cin >> n >> m >> d; - - vector p(n + 1); - vector pos(n + 1); - - // 读取排列 p,并构建位置数组 pos - for (int i = 1; i <= n; i++) { - cin >> p[i]; - pos[p[i]] = i; - } - - vector a(m); - for (int i = 0; i < m; i++) { - cin >> a[i]; - } - - int min_operations = INT_MAX; - - // 遍历数组 a 的相邻元素 - for (int i = 0; i < m - 1; i++) { - int current_pos = pos[a[i]]; - int next_pos = pos[a[i + 1]]; - - // 检查 pos[a[i]] < pos[a[i+1]] <= pos[a[i]] + d 是否成立 - if (current_pos < next_pos && next_pos <= current_pos + d) { - // 计算需要的最少操作次数 - int distance = next_pos - current_pos; - - // Case 1: 交换 current_pos 和 next_pos - min_operations = min(min_operations, distance); - - // Case 2: 如果 next_pos + d <= n,考虑使 pos[a[i+1]] 超过 pos[a[i]] + d - if (current_pos + d + 1 <= n) { - min_operations = min(min_operations, d + 1 - distance); - } - } else { - min_operations = 0; - } - } - - cout << min_operations << endl; - return 0; -} - -``` - -时间复杂度为 O(m) diff --git a/problems/kamacoder/0164.升序数组.md b/problems/kamacoder/0164.升序数组.md deleted file mode 100644 index 2a35b715..00000000 --- a/problems/kamacoder/0164.升序数组.md +++ /dev/null @@ -1,81 +0,0 @@ -# 升序数组 - -[题目链接](https://kamacoder.com/problempage.php?pid=1241) - -## 解题思路 - -贪心思路 - -- **计算相邻元素差值**: - - 对于数组 `a`,计算每对相邻元素的差值 `diff[i] = a[i+1] - a[i]`。 - - 如果 `diff[i]` 为负数,意味着 `a[i+1]` 比 `a[i]` 小或相等,需要通过操作使 `a[i+1]` 变大。 - -- **确定最小操作次数**: - - 计算所有相邻元素中的最小差值 `minDifference`,即 `minDifference = min(diff[i])`。 - - 如果 `minDifference` 为负数或零,则需要进行 `-minDifference + 1` 次操作,使得 `a[i+1]` 大于 `a[i]`,从而使数组严格递增。 - -- **实现细节**: - - 遍历数组的每对相邻元素,找出最小的差值。 - - 根据最小差值,计算出最少的操作次数。 - - - -```CPP -#include -#include -#include - -using namespace std; - -int main() -{ - int n; - cin >> n; - - vector arr(n); // 用于存储输入数组 - vector differences; // 用于存储相邻元素的差值 - - for(int i = 0; i < n; i++) { - cin >> arr[i]; - if(i > 0) differences.push_back(arr[i] - arr[i - 1]); - - } - - int minDifference = INT_MAX; - - // 寻找最小的差值 - for(int diff : differences) { - if(diff < minDifference) { - minDifference = diff; - } - } - - // 如果最小差值是负数或零,计算所需的操作次数 - int minOperations = max(0, -minDifference + 1); - - cout << minOperations << endl; - - return 0; -} - -``` -关于 `-minDifference + 1` 为什么要 + 1 解释: - -对于数组 `a` 中相邻的两个元素 `a[i]` 和 `a[i+1]`,我们计算它们的差值 `diff = a[i+1] - a[i]`。 - -- **目标**:要使 `a[i] < a[i+1]`,需要 `diff > 0`。 -- 如果 `diff < 0`,说明 `a[i+1]` 比 `a[i]` 小,这时候 `a` 不是严格递增的。 -- 如果 `diff = 0`,说明 `a[i+1]` 和 `a[i]` 相等,这时也不满足严格递增。 - -解释 `-minDifference + 1` - -1. **当 `minDifference < 0` 时**: - - 假设 `minDifference` 是所有相邻差值中的最小值,并且它是一个负数。 - - 例如,`minDifference = -3`,表示 `a[i+1] - a[i] = -3`,也就是 `a[i+1]` 比 `a[i]` 小 `3`。 - - 要让 `a[i+1] > a[i]`,我们至少需要使 `a[i+1] - a[i]` 从 `-3` 增加到 `1`。因此需要增加 `4`,即 `(-(-3)) + 1 = 3 + 1 = 4` 次操作。 - -2. **当 `minDifference = 0` 时**: - - `minDifference` 等于 `0`,表示 `a[i+1] - a[i] = 0`,即 `a[i+1]` 和 `a[i]` 相等。 - - 为了使 `a[i+1] > a[i]`,我们至少需要进行一次操作,使得 `a[i+1]` 大于 `a[i]`。 - - diff --git a/problems/kamacoder/0165.最大字典序无重复串.md b/problems/kamacoder/0165.最大字典序无重复串.md deleted file mode 100644 index c7be98d2..00000000 --- a/problems/kamacoder/0165.最大字典序无重复串.md +++ /dev/null @@ -1,82 +0,0 @@ - -# 最大字典序无重复串 - -[题目链接](https://kamacoder.com/problempage.php?pid=1243) - - -## 解题思路 - -贪心思路 - -为了保证字典序最大,我们优先放置字母 `b`,然后再放置字母 `a`。在放置字符时,我们还需注意不能超过连续 `k` 次相同字符: - -- 如果当前已经连续放置了 `k` 次相同字符,必须切换到另一个字符。 -- 每次放置字符后,相应的字符数量减少,同时更新当前字符的连续计数。 - -实现步骤: - -- **初始化**:根据输入的 `x`, `y`, `k` 值,检查是否有可能构造出满足条件的字符串。初始化结果字符串的大小,并设置初始计数器。 -- **循环放置字符**: - - 优先放置字符 `b`,如果 `b` 的数量已经足够,或者已经放置了 `k` 次字符 `b`,则放置字符 `a`。 - - 如果已经放置了 `k` 次相同字符,则强制切换到另一个字符。 - -C++代码如下: - -```CPP -#include -#include -using namespace std; - -int main() { - int countA, countB, maxRepeat; - cin >> countA >> countB >> maxRepeat; - - // 检查是否有可能生成满足条件的字符串 - if (countA > (countB + 1) * maxRepeat || countB > (countA + 1) * maxRepeat) { - cout << -1 << endl; - return 0; - } - - string result(countA + countB, ' '); // 预先分配字符串大小 - int currentA = 0, currentB = 0; // 当前连续 'a' 和 'b' 的计数 - int pos = 0; // 当前填充位置 - - while (countA > 0 || countB > 0) { - // 当可以继续添加 'a' 或 'b' 且没有超过最大连续限制时 - if (currentA < maxRepeat && currentB < maxRepeat) { - if (countA <= countB * maxRepeat) { - result[pos++] = 'b'; - countB--; - currentB++; - currentA = 0; - } else { - result[pos++] = 'a'; - countA--; - currentA++; - currentB = 0; - } - } - - // 当当前字符达到最大连续限制时,切换到另一个字符 - if (currentA == maxRepeat || currentB == maxRepeat) { - if (result[pos - 1] == 'a') { - result[pos++] = 'b'; - countB--; - currentB = 1; - currentA = 0; - } else { - result[pos++] = 'a'; - countA--; - currentA = 1; - currentB = 0; - } - } - } - - cout << result << endl; - return 0; -} - -``` - -时间复杂度:O(n)