diff --git a/problems/0046.全排列.md b/problems/0046.全排列.md index 638a2a7c..1ef80a14 100644 --- a/problems/0046.全排列.md +++ b/problems/0046.全排列.md @@ -42,7 +42,8 @@ 我以[1,2,3]为例,抽象成树形结构如下: -![46.全排列](https://code-thinking-1253855093.file.myqcloud.com/pics/20211027181706.png) + +![全排列](https://code-thinking-1253855093.file.myqcloud.com/pics/20240803180318.png) ### 回溯三部曲 @@ -54,7 +55,7 @@ 但排列问题需要一个used数组,标记已经选择的元素,如图橘黄色部分所示: -![46.全排列](https://code-thinking-1253855093.file.myqcloud.com/pics/20211027181706.png) +![全排列](https://code-thinking-1253855093.file.myqcloud.com/pics/20240803180318.png) 代码如下: @@ -66,7 +67,7 @@ void backtracking (vector& nums, vector& used) * 递归终止条件 -![46.全排列](https://code-thinking-1253855093.file.myqcloud.com/pics/20201209174225145.png) +![全排列](https://code-thinking-1253855093.file.myqcloud.com/pics/20240803180318.png) 可以看出叶子节点,就是收割结果的地方。 diff --git a/problems/0494.目标和.md b/problems/0494.目标和.md index 92616ed1..9d13067e 100644 --- a/problems/0494.目标和.md +++ b/problems/0494.目标和.md @@ -134,17 +134,17 @@ x = (target + sum) / 2 大家看到(target + sum) / 2 应该担心计算的过程中向下取整有没有影响。 -这么担心就对了,例如sum 是5,S是2的话其实就是无解的,所以: +这么担心就对了,例如sum是5,target是2 的话其实就是无解的,所以: ```CPP (C++代码中,输入的S 就是题目描述的 target) -if ((S + sum) % 2 == 1) return 0; // 此时没有方案 +if ((target + sum) % 2 == 1) return 0; // 此时没有方案 ``` -同时如果 S的绝对值已经大于sum,那么也是没有方案的。 +同时如果target 的绝对值已经大于sum,那么也是没有方案的。 + ```CPP -(C++代码中,输入的S 就是题目描述的 target) -if (abs(S) > sum) return 0; // 此时没有方案 +if (abs(target) > sum) return 0; // 此时没有方案 ``` 再回归到01背包问题,为什么是01背包呢? @@ -213,9 +213,9 @@ dp[j]其他下标对应的数值也应该初始化为0,从递推公式也可 5. 举例推导dp数组 -输入:nums: [1, 1, 1, 1, 1], S: 3 +输入:nums: [1, 1, 1, 1, 1], target: 3 -bagSize = (S + sum) / 2 = (3 + 5) / 2 = 4 +bagSize = (target + sum) / 2 = (3 + 5) / 2 = 4 dp数组状态变化如下: @@ -226,12 +226,12 @@ C++代码如下: ```CPP class Solution { public: - int findTargetSumWays(vector& nums, int S) { + int findTargetSumWays(vector& nums, int target) { int sum = 0; for (int i = 0; i < nums.size(); i++) sum += nums[i]; - if (abs(S) > sum) return 0; // 此时没有方案 - if ((S + sum) % 2 == 1) return 0; // 此时没有方案 - int bagSize = (S + sum) / 2; + if (abs(target) > sum) return 0; // 此时没有方案 + if ((target + sum) % 2 == 1) return 0; // 此时没有方案 + int bagSize = (target + sum) / 2; vector dp(bagSize + 1, 0); dp[0] = 1; for (int i = 0; i < nums.size(); i++) { @@ -655,3 +655,52 @@ public class Solution + + +class Solution { +public: + int findTargetSumWays(vector& nums, int target) { + int sum = 0; + for (int i = 0; i < nums.size(); i++) sum += nums[i]; + if (abs(target) > sum) return 0; // 此时没有方案 + if ((target + sum) % 2 == 1) return 0; // 此时没有方案 + int bagSize = (target + sum) / 2; + + vector> dp(nums.size(), vector(bagSize + 1, 0)); + + if (nums[0] <= bagSize) dp[0][nums[0]] = 1; + + dp[0][0] = 1; + + int numZero = 0; + for (int i = 0; i < nums.size(); i++) { + if (nums[i] == 0) numZero++; + dp[i][0] = (int) pow(2.0, numZero); + } + + for (int i = 1; i < nums.size(); i++) { + for (int j = 0; j <= bagSize; j++) { + if (nums[i] > j) dp[i][j] = dp[i - 1][j]; + else dp[i][j] = dp[i - 1][j] + dp[i - 1][j - nums[i]]; + } + } + for (int i = 0; i < nums.size(); i++) { + for (int j = 0; j <= bagSize; j++) { + cout << dp[i][j] << " "; + } + cout << endl; + } + return dp[nums.size() - 1][bagSize]; + } +}; + +1 1 0 0 0 +1 2 1 0 0 +1 3 3 1 0 +1 4 6 4 1 +1 5 10 10 5 + +初始化 如果没有0, dp[i][0] = 1; 即所有元素都不取。 + +用元素 取与不取来举例 + diff --git a/problems/kamacoder/0094.城市间货物运输I-SPFA.md b/problems/kamacoder/0094.城市间货物运输I-SPFA.md index 5fe06d34..3aa53655 100644 --- a/problems/kamacoder/0094.城市间货物运输I-SPFA.md +++ b/problems/kamacoder/0094.城市间货物运输I-SPFA.md @@ -64,7 +64,7 @@ ![](https://code-thinking-1253855093.file.myqcloud.com/pics/20240328104119.png) -本图中,对所有边进行松弛,真正有效的松弛,只有松弛 边(节点1->节点2) 和 边(节点1->节点5) 。 +本图中,对所有边进行松弛,真正有效的松弛,只有松弛 边(节点1->节点2) 和 边(节点1->节点3) 。 而松弛 边(节点4->节点6) ,边(节点5->节点3)等等 都是无效的操作,因为 节点4 和 节点 5 都是没有被计算过的节点。 diff --git a/problems/kamacoder/0151.手机流畅运行的秘密.md b/problems/kamacoder/0151.手机流畅运行的秘密.md new file mode 100644 index 00000000..3859f7b0 --- /dev/null +++ b/problems/kamacoder/0151.手机流畅运行的秘密.md @@ -0,0 +1,127 @@ +# 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 new file mode 100644 index 00000000..afb5d8ea --- /dev/null +++ b/problems/kamacoder/0152.小米手机通信校准.md @@ -0,0 +1,121 @@ + + +# 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() + + +```