From a8585045056e56fa2bf9707cd6fe5eadc6b7bcd6 Mon Sep 17 00:00:00 2001 From: yanglbme Date: Fri, 22 Dec 2023 08:48:11 +0800 Subject: [PATCH] feat: add solutions to lc problems: No.34,1870,1894 --- README.md | 1 - README_EN.md | 1 - .../README.md | 73 ++++----- .../README_EN.md | 68 ++++---- .../Solution.ts | 9 +- .../README.md | 4 +- .../README_EN.md | 4 +- .../README.md | 16 +- .../README_EN.md | 11 ++ .../README.md | 155 ++++++++---------- .../README_EN.md | 110 ++++++++----- .../Solution.cpp | 13 +- .../Solution.go | 16 +- .../Solution.java | 22 +-- .../Solution.py | 9 +- .../Solution.rs | 25 ++- .../Solution.ts | 13 ++ .../README.md | 16 +- 18 files changed, 302 insertions(+), 264 deletions(-) create mode 100644 solution/1800-1899/1894.Find the Student that Will Replace the Chalk/Solution.ts diff --git a/README.md b/README.md index 43dbdfca64534..d8fc9ae3908c8 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,6 @@ - [在排序数组中查找元素的第一个和最后一个位置](/solution/0000-0099/0034.Find%20First%20and%20Last%20Position%20of%20Element%20in%20Sorted%20Array/README.md) - `二分查找` - [准时到达的列车最小时速](/solution/1800-1899/1870.Minimum%20Speed%20to%20Arrive%20on%20Time/README.md) - `二分查找` -- [找到需要补充粉笔的学生编号](/solution/1800-1899/1894.Find%20the%20Student%20that%20Will%20Replace%20the%20Chalk/README.md) - `二分查找` - [可移除字符的最大数目](/solution/1800-1899/1898.Maximum%20Number%20of%20Removable%20Characters/README.md) - `二分查找` - [排序数组](/solution/0900-0999/0912.Sort%20an%20Array/README.md) - `快速排序`、`归并排序` - [字符串相加](/solution/0400-0499/0415.Add%20Strings/README.md) - `高精度加法` diff --git a/README_EN.md b/README_EN.md index a1b12f59c58c1..72060d68c0d63 100644 --- a/README_EN.md +++ b/README_EN.md @@ -43,7 +43,6 @@ The repository is maintained by the Doocs community, and please give us a [star] - [Find First and Last Position of Element in Sorted Array](/solution/0000-0099/0034.Find%20First%20and%20Last%20Position%20of%20Element%20in%20Sorted%20Array/README_EN.md) - `Binary search` - [Minimum Speed to Arrive on Time](/solution/1800-1899/1870.Minimum%20Speed%20to%20Arrive%20on%20Time/README_EN.md) - `Binary search` -- [Find the Student that Will Replace the Chalk](/solution/1800-1899/1894.Find%20the%20Student%20that%20Will%20Replace%20the%20Chalk/README_EN.md) - `Binary search` - [Maximum Number of Removable Characters](/solution/1800-1899/1898.Maximum%20Number%20of%20Removable%20Characters/README_EN.md) - `Binary search` - [Sort an Array](/solution/0900-0999/0912.Sort%20an%20Array/README_EN.md) - `Quick Sort`, `Merge Sort` - [Add Strings](/solution/0400-0499/0415.Add%20Strings/README_EN.md) - `Addition of large numbers` diff --git a/solution/0000-0099/0034.Find First and Last Position of Element in Sorted Array/README.md b/solution/0000-0099/0034.Find First and Last Position of Element in Sorted Array/README.md index ba756d39383e7..1815b5d0d27de 100644 --- a/solution/0000-0099/0034.Find First and Last Position of Element in Sorted Array/README.md +++ b/solution/0000-0099/0034.Find First and Last Position of Element in Sorted Array/README.md @@ -93,16 +93,16 @@ int search(int left, int right) { } ``` -做二分题目时,可以按照以下步骤: +做二分题目时,可以按照以下套路: -1. 写出循环条件:`while (left < right)`,注意是 `left < right`,而非 `left <= right`; -1. 循环体内,先无脑写出 `mid = (left + right) >> 1`; -1. 根据具体题目,实现 `check()` 函数(有时很简单的逻辑,可以不定义 `check`),想一下究竟要用 `right = mid`(模板 1) 还是 `left = mid`(模板 2); - - 如果 `right = mid`,那么无脑写出 else 语句 `left = mid + 1`,并且不需要更改 mid 的计算,即保持 `mid = (left + right) >> 1`; - - 如果 `left = mid`,那么无脑写出 else 语句 `right = mid - 1`,并且在 mid 计算时补充 +1,即 `mid = (left + right + 1) >> 1`。 -1. 循环结束时,left 与 right 相等。 +1. 写出循环条件 $left < right$; +1. 循环体内,不妨先写 $mid = \lfloor \frac{left + right}{2} \rfloor$; +1. 根据具体题目,实现 $check()$ 函数(有时很简单的逻辑,可以不定义 $check$),想一下究竟要用 $right = mid$(模板 $1$) 还是 $left = mid$(模板 $2$); +     - 如果 $right = mid$,那么写出 else 语句 $left = mid + 1$,并且不需要更改 mid 的计算,即保持 $mid = \lfloor \frac{left + right}{2} \rfloor$; +     - 如果 $left = mid$,那么写出 else 语句 $right = mid - 1$,并且在 $mid$ 计算时补充 +1,即 $mid = \lfloor \frac{left + right + 1}{2} \rfloor$; +1. 循环结束时,$left$ 与 $right$ 相等。 -注意,这两个模板的优点是始终保持答案位于二分区间内,二分结束条件对应的值恰好在答案所处的位置。 对于可能无解的情况,只要判断二分结束后的 left 或者 right 是否满足题意即可。 +注意,这两个模板的优点是始终保持答案位于二分区间内,二分结束条件对应的值恰好在答案所处的位置。 对于可能无解的情况,只要判断二分结束后的 $left$ 或者 $right$ 是否满足题意即可。 @@ -159,34 +159,6 @@ public: }; ``` -### **JavaScript** - -```js -/** - * @param {number[]} nums - * @param {number} target - * @return {number[]} - */ -var searchRange = function (nums, target) { - function search(x) { - let left = 0, - right = nums.length; - while (left < right) { - const mid = (left + right) >> 1; - if (nums[mid] >= x) { - right = mid; - } else { - left = mid + 1; - } - } - return left; - } - const l = search(target); - const r = search(target + 1); - return l == r ? [-1, -1] : [l, r - 1]; -}; -``` - ### **Go** ```go @@ -233,6 +205,33 @@ impl Solution { ```ts function searchRange(nums: number[], target: number): number[] { + const search = (x: number): number => { + let [left, right] = [0, nums.length]; + while (left < right) { + const mid = (left + right) >> 1; + if (nums[mid] >= x) { + right = mid; + } else { + left = mid + 1; + } + } + return left; + }; + const l = search(target); + const r = search(target + 1); + return l === r ? [-1, -1] : [l, r - 1]; +} +``` + +### **JavaScript** + +```js +/** + * @param {number[]} nums + * @param {number} target + * @return {number[]} + */ +var searchRange = function (nums, target) { function search(x) { let left = 0, right = nums.length; @@ -249,7 +248,7 @@ function searchRange(nums: number[], target: number): number[] { const l = search(target); const r = search(target + 1); return l == r ? [-1, -1] : [l, r - 1]; -} +}; ``` ### **...** diff --git a/solution/0000-0099/0034.Find First and Last Position of Element in Sorted Array/README_EN.md b/solution/0000-0099/0034.Find First and Last Position of Element in Sorted Array/README_EN.md index b018d9b28fe1b..0c0b1f8e18cec 100644 --- a/solution/0000-0099/0034.Find First and Last Position of Element in Sorted Array/README_EN.md +++ b/solution/0000-0099/0034.Find First and Last Position of Element in Sorted Array/README_EN.md @@ -79,6 +79,17 @@ int search(int left, int right) { } ``` +When doing binary search problems, you can follow the following routine: + +1. Write out the loop condition $left < right$; +2. Inside the loop, you might as well write $mid = \lfloor \frac{left + right}{2} \rfloor$ first; +3. According to the specific problem, implement the $check()$ function (sometimes the logic is very simple, you can not define $check$), think about whether to use $right = mid$ (Template $1$) or $left = mid$ (Template $2$); + - If $right = mid$, then write the else statement $left = mid + 1$, and there is no need to change the calculation of $mid$, that is, keep $mid = \lfloor \frac{left + right}{2} \rfloor$; + - If $left = mid$, then write the else statement $right = mid - 1$, and add +1 when calculating $mid$, that is, $mid = \lfloor \frac{left + right + 1}{2} \rfloor$; +4. When the loop ends, $left$ equals $right$. + +Note that the advantage of these two templates is that they always keep the answer within the binary search interval, and the value corresponding to the end condition of the binary search is exactly at the position of the answer. For the case that may have no solution, just check whether the $left$ or $right$ after the binary search ends satisfies the problem. + ### **Python3** @@ -130,34 +141,6 @@ public: }; ``` -### **JavaScript** - -```js -/** - * @param {number[]} nums - * @param {number} target - * @return {number[]} - */ -var searchRange = function (nums, target) { - function search(x) { - let left = 0, - right = nums.length; - while (left < right) { - const mid = (left + right) >> 1; - if (nums[mid] >= x) { - right = mid; - } else { - left = mid + 1; - } - } - return left; - } - const l = search(target); - const r = search(target + 1); - return l == r ? [-1, -1] : [l, r - 1]; -}; -``` - ### **Go** ```go @@ -204,6 +187,33 @@ impl Solution { ```ts function searchRange(nums: number[], target: number): number[] { + const search = (x: number): number => { + let [left, right] = [0, nums.length]; + while (left < right) { + const mid = (left + right) >> 1; + if (nums[mid] >= x) { + right = mid; + } else { + left = mid + 1; + } + } + return left; + }; + const l = search(target); + const r = search(target + 1); + return l === r ? [-1, -1] : [l, r - 1]; +} +``` + +### **JavaScript** + +```js +/** + * @param {number[]} nums + * @param {number} target + * @return {number[]} + */ +var searchRange = function (nums, target) { function search(x) { let left = 0, right = nums.length; @@ -220,7 +230,7 @@ function searchRange(nums: number[], target: number): number[] { const l = search(target); const r = search(target + 1); return l == r ? [-1, -1] : [l, r - 1]; -} +}; ``` ### **...** diff --git a/solution/0000-0099/0034.Find First and Last Position of Element in Sorted Array/Solution.ts b/solution/0000-0099/0034.Find First and Last Position of Element in Sorted Array/Solution.ts index 8441ad17e1bbe..001c5ba4dba1e 100644 --- a/solution/0000-0099/0034.Find First and Last Position of Element in Sorted Array/Solution.ts +++ b/solution/0000-0099/0034.Find First and Last Position of Element in Sorted Array/Solution.ts @@ -1,7 +1,6 @@ function searchRange(nums: number[], target: number): number[] { - function search(x) { - let left = 0, - right = nums.length; + const search = (x: number): number => { + let [left, right] = [0, nums.length]; while (left < right) { const mid = (left + right) >> 1; if (nums[mid] >= x) { @@ -11,8 +10,8 @@ function searchRange(nums: number[], target: number): number[] { } } return left; - } + }; const l = search(target); const r = search(target + 1); - return l == r ? [-1, -1] : [l, r - 1]; + return l === r ? [-1, -1] : [l, r - 1]; } diff --git a/solution/1600-1699/1671.Minimum Number of Removals to Make Mountain Array/README.md b/solution/1600-1699/1671.Minimum Number of Removals to Make Mountain Array/README.md index 2591c48e172a2..efe07d5b8af3e 100644 --- a/solution/1600-1699/1671.Minimum Number of Removals to Make Mountain Array/README.md +++ b/solution/1600-1699/1671.Minimum Number of Removals to Make Mountain Array/README.md @@ -219,9 +219,9 @@ function minimumMountainRemovals(nums: number[]): number { } ``` -### **TypeScript** +### **Rust** -```ts +```rust impl Solution { pub fn minimum_mountain_removals(nums: Vec) -> i32 { let n = nums.len(); diff --git a/solution/1600-1699/1671.Minimum Number of Removals to Make Mountain Array/README_EN.md b/solution/1600-1699/1671.Minimum Number of Removals to Make Mountain Array/README_EN.md index 0c483fbc51c62..cac1ba743c46a 100644 --- a/solution/1600-1699/1671.Minimum Number of Removals to Make Mountain Array/README_EN.md +++ b/solution/1600-1699/1671.Minimum Number of Removals to Make Mountain Array/README_EN.md @@ -209,9 +209,9 @@ function minimumMountainRemovals(nums: number[]): number { } ``` -### **TypeScript** +### **Rust** -```ts +```rust impl Solution { pub fn minimum_mountain_removals(nums: Vec) -> i32 { let n = nums.len(); diff --git a/solution/1800-1899/1870.Minimum Speed to Arrive on Time/README.md b/solution/1800-1899/1870.Minimum Speed to Arrive on Time/README.md index 5d82cfe9e7291..2d921928eb591 100644 --- a/solution/1800-1899/1870.Minimum Speed to Arrive on Time/README.md +++ b/solution/1800-1899/1870.Minimum Speed to Arrive on Time/README.md @@ -112,16 +112,16 @@ int search(int left, int right) { } ``` -做二分题目时,可以按照以下步骤: +做二分题目时,可以按照以下套路: -1. 写出循环条件:`while (left < right)`,注意是 `left < right`,而非 `left <= right`; -1. 循环体内,先无脑写出 `mid = (left + right) >> 1`; -1. 根据具体题目,实现 `check()` 函数(有时很简单的逻辑,可以不定义 `check`),想一下究竟要用 `right = mid`(模板 1) 还是 `left = mid`(模板 2); - - 如果 `right = mid`,那么无脑写出 else 语句 `left = mid + 1`,并且不需要更改 mid 的计算,即保持 `mid = (left + right) >> 1`; - - 如果 `left = mid`,那么无脑写出 else 语句 `right = mid - 1`,并且在 mid 计算时补充 +1,即 `mid = (left + right + 1) >> 1`。 -1. 循环结束时,left 与 right 相等。 +1. 写出循环条件 $left < right$; +1. 循环体内,不妨先写 $mid = \lfloor \frac{left + right}{2} \rfloor$; +1. 根据具体题目,实现 $check()$ 函数(有时很简单的逻辑,可以不定义 $check$),想一下究竟要用 $right = mid$(模板 $1$) 还是 $left = mid$(模板 $2$); +     - 如果 $right = mid$,那么写出 else 语句 $left = mid + 1$,并且不需要更改 mid 的计算,即保持 $mid = \lfloor \frac{left + right}{2} \rfloor$; +     - 如果 $left = mid$,那么写出 else 语句 $right = mid - 1$,并且在 $mid$ 计算时补充 +1,即 $mid = \lfloor \frac{left + right + 1}{2} \rfloor$; +1. 循环结束时,$left$ 与 $right$ 相等。 -注意,这两个模板的优点是始终保持答案位于二分区间内,二分结束条件对应的值恰好在答案所处的位置。 对于可能无解的情况,只要判断二分结束后的 left 或者 right 是否满足题意即可。 +注意,这两个模板的优点是始终保持答案位于二分区间内,二分结束条件对应的值恰好在答案所处的位置。 对于可能无解的情况,只要判断二分结束后的 $left$ 或者 $right$ 是否满足题意即可。 diff --git a/solution/1800-1899/1870.Minimum Speed to Arrive on Time/README_EN.md b/solution/1800-1899/1870.Minimum Speed to Arrive on Time/README_EN.md index 588262b9abd13..bd845221efa41 100644 --- a/solution/1800-1899/1870.Minimum Speed to Arrive on Time/README_EN.md +++ b/solution/1800-1899/1870.Minimum Speed to Arrive on Time/README_EN.md @@ -102,6 +102,17 @@ int search(int left, int right) { } ``` +When doing binary search problems, you can follow the following routine: + +1. Write out the loop condition $left < right$; +2. Inside the loop, you might as well write $mid = \lfloor \frac{left + right}{2} \rfloor$ first; +3. According to the specific problem, implement the $check()$ function (sometimes the logic is very simple, you can not define $check$), think about whether to use $right = mid$ (Template $1$) or $left = mid$ (Template $2$); + - If $right = mid$, then write the else statement $left = mid + 1$, and there is no need to change the calculation of $mid$, that is, keep $mid = \lfloor \frac{left + right}{2} \rfloor$; + - If $left = mid$, then write the else statement $right = mid - 1$, and add +1 when calculating $mid$, that is, $mid = \lfloor \frac{left + right + 1}{2} \rfloor$; +4. When the loop ends, $left$ equals $right$. + +Note that the advantage of these two templates is that they always keep the answer within the binary search interval, and the value corresponding to the end condition of the binary search is exactly at the position of the answer. For the case that may have no solution, just check whether the $left$ or $right$ after the binary search ends satisfies the problem. + ### **Python3** diff --git a/solution/1800-1899/1894.Find the Student that Will Replace the Chalk/README.md b/solution/1800-1899/1894.Find the Student that Will Replace the Chalk/README.md index 8d150771ebcc6..fc9519935e519 100644 --- a/solution/1800-1899/1894.Find the Student that Will Replace the Chalk/README.md +++ b/solution/1800-1899/1894.Find the Student that Will Replace the Chalk/README.md @@ -61,58 +61,13 @@ -**方法一:前缀和 + 二分查找** +**方法一:求和取余 + 模拟** -以下是二分查找的两个通用模板: +由于学生的回答是一轮一轮循环进行的,因此我们可以将所有学生需要消耗的粉笔数加起来,得到一个总数 $s$。然后我们对 $k$ 取 $s$ 的余数,即可知道最后一轮结束后剩余的粉笔数。 -模板 1: +接下来,我们只需要模拟最后一轮即可。初始时,剩余的粉笔数为 $k$,编号为 $0$ 的学生开始回答问题。当剩余的粉笔数小于当前学生需要的粉笔数时,当前学生需要补充粉笔,我们直接返回当前学生的编号 $i$ 即可。否则,我们将剩余的粉笔数减去当前学生需要的粉笔数,并将当前学生的编号 $i$ 加一,进行下一次模拟。 -```java -boolean check(int x) { -} - -int search(int left, int right) { - while (left < right) { - int mid = (left + right) >> 1; - if (check(mid)) { - right = mid; - } else { - left = mid + 1; - } - } - return left; -} -``` - -模板 2: - -```java -boolean check(int x) { -} - -int search(int left, int right) { - while (left < right) { - int mid = (left + right + 1) >> 1; - if (check(mid)) { - left = mid; - } else { - right = mid - 1; - } - } - return left; -} -``` - -做二分题目时,可以按照以下步骤: - -1. 写出循环条件:`while (left < right)`,注意是 `left < right`,而非 `left <= right`; -1. 循环体内,先无脑写出 `mid = (left + right) >> 1`; -1. 根据具体题目,实现 `check()` 函数(有时很简单的逻辑,可以不定义 `check`),想一下究竟要用 `right = mid`(模板 1) 还是 `left = mid`(模板 2); - - 如果 `right = mid`,那么无脑写出 else 语句 `left = mid + 1`,并且不需要更改 mid 的计算,即保持 `mid = (left + right) >> 1`; - - 如果 `left = mid`,那么无脑写出 else 语句 `right = mid - 1`,并且在 mid 计算时补充 +1,即 `mid = (left + right + 1) >> 1`。 -1. 循环结束时,left 与 right 相等。 - -注意,这两个模板的优点是始终保持答案位于二分区间内,二分结束条件对应的值恰好在答案所处的位置。 对于可能无解的情况,只要判断二分结束后的 left 或者 right 是否满足题意即可。 +时间复杂度 $O(n)$,其中 $n$ 是学生的数量。空间复杂度 $O(1)$。 @@ -123,9 +78,12 @@ int search(int left, int right) { ```python class Solution: def chalkReplacer(self, chalk: List[int], k: int) -> int: - s = list(accumulate(chalk)) - k %= s[-1] - return bisect_right(s, k) + s = sum(chalk) + k %= s + for i, x in enumerate(chalk): + if k < x: + return i + k -= x ``` ### **Java** @@ -135,22 +93,17 @@ class Solution: ```java class Solution { public int chalkReplacer(int[] chalk, int k) { - int n = chalk.length; - long[] preSum = new long[n + 1]; - for (int i = 0; i < n; ++i) { - preSum[i + 1] = preSum[i] + chalk[i]; + long s = 0; + for (int x : chalk) { + s += x; } - k %= preSum[n]; - int left = 0, right = n - 1; - while (left < right) { - int mid = (left + right) >> 1; - if (preSum[mid + 1] > k) { - right = mid; - } else { - left = mid + 1; + k %= s; + for (int i = 0;; ++i) { + if (k < chalk[i]) { + return i; } + k -= chalk[i]; } - return left; } } ``` @@ -161,11 +114,14 @@ class Solution { class Solution { public: int chalkReplacer(vector& chalk, int k) { - int n = chalk.size(); - vector s(n, chalk[0]); - for (int i = 1; i < n; ++i) s[i] = s[i - 1] + chalk[i]; - k %= s[n - 1]; - return upper_bound(s.begin(), s.end(), k) - s.begin(); + long long s = accumulate(chalk.begin(), chalk.end(), 0LL); + k %= s; + for (int i = 0;; ++i) { + if (k < chalk[i]) { + return i; + } + k -= chalk[i]; + } } }; ``` @@ -174,13 +130,17 @@ public: ```go func chalkReplacer(chalk []int, k int) int { - n := len(chalk) - s := make([]int, n+1) - for i := 0; i < n; i++ { - s[i+1] = s[i] + chalk[i] + s := 0 + for _, x := range chalk { + s += x + } + k %= s + for i := 0; ; i++ { + if k < chalk[i] { + return i + } + k -= chalk[i] } - k %= s[n] - return sort.Search(n, func(i int) bool { return s[i+1] > k }) } ``` @@ -189,19 +149,36 @@ func chalkReplacer(chalk []int, k int) int { ```rust impl Solution { pub fn chalk_replacer(chalk: Vec, k: i32) -> i32 { - let pre_sum: Vec = chalk - .into_iter() - .map(|x| x as i64) - .scan(0, |state, x| { - *state += x; - Some(*state) - }) - .collect(); - - pre_sum.binary_search(&((k as i64) % pre_sum.last().unwrap())).map_or_else( - |e| e, - |v| v + 1 - ) as i32 + let mut s: i64 = chalk + .iter() + .map(|&x| x as i64) + .sum(); + let mut k = (k as i64) % s; + for (i, &x) in chalk.iter().enumerate() { + if k < (x as i64) { + return i as i32; + } + k -= x as i64; + } + 0 + } +} +``` + +### **TypeScript** + +```ts +function chalkReplacer(chalk: number[], k: number): number { + let s = 0; + for (const x of chalk) { + s += x; + } + k %= s; + for (let i = 0; ; ++i) { + if (k < chalk[i]) { + return i; + } + k -= chalk[i]; } } ``` diff --git a/solution/1800-1899/1894.Find the Student that Will Replace the Chalk/README_EN.md b/solution/1800-1899/1894.Find the Student that Will Replace the Chalk/README_EN.md index d427ed28f408d..63d62b17f6ffa 100644 --- a/solution/1800-1899/1894.Find the Student that Will Replace the Chalk/README_EN.md +++ b/solution/1800-1899/1894.Find the Student that Will Replace the Chalk/README_EN.md @@ -55,7 +55,13 @@ Student number 1 does not have enough chalk, so they will have to replace it. ## Solutions -PreSum and Binary search. +**Solution 1: Sum and Modulo + Simulation** + +Since the students' answers are conducted in rounds, we can add up the chalk needed by all students to get a total $s$. Then we take the remainder of $k$ by $s$, which can tell us the remaining number of chalks after the last round. + +Next, we just need to simulate the last round. Initially, the remaining number of chalks is $k$, and the student with the number $0$ starts to answer the question. When the remaining number of chalks is less than the current student needs, the current student needs to replenish the chalk, and we directly return the current student's number $i$. Otherwise, we subtract the chalk needed by the current student from the remaining chalk, and add one to the current student's number $i$ for the next simulation. + +The time complexity is $O(n)$, where $n$ is the number of students. The space complexity is $O(1)$. @@ -64,9 +70,12 @@ PreSum and Binary search. ```python class Solution: def chalkReplacer(self, chalk: List[int], k: int) -> int: - s = list(accumulate(chalk)) - k %= s[-1] - return bisect_right(s, k) + s = sum(chalk) + k %= s + for i, x in enumerate(chalk): + if k < x: + return i + k -= x ``` ### **Java** @@ -74,22 +83,17 @@ class Solution: ```java class Solution { public int chalkReplacer(int[] chalk, int k) { - int n = chalk.length; - long[] preSum = new long[n + 1]; - for (int i = 0; i < n; ++i) { - preSum[i + 1] = preSum[i] + chalk[i]; + long s = 0; + for (int x : chalk) { + s += x; } - k %= preSum[n]; - int left = 0, right = n - 1; - while (left < right) { - int mid = (left + right) >> 1; - if (preSum[mid + 1] > k) { - right = mid; - } else { - left = mid + 1; + k %= s; + for (int i = 0;; ++i) { + if (k < chalk[i]) { + return i; } + k -= chalk[i]; } - return left; } } ``` @@ -100,11 +104,14 @@ class Solution { class Solution { public: int chalkReplacer(vector& chalk, int k) { - int n = chalk.size(); - vector s(n, chalk[0]); - for (int i = 1; i < n; ++i) s[i] = s[i - 1] + chalk[i]; - k %= s[n - 1]; - return upper_bound(s.begin(), s.end(), k) - s.begin(); + long long s = accumulate(chalk.begin(), chalk.end(), 0LL); + k %= s; + for (int i = 0;; ++i) { + if (k < chalk[i]) { + return i; + } + k -= chalk[i]; + } } }; ``` @@ -113,13 +120,17 @@ public: ```go func chalkReplacer(chalk []int, k int) int { - n := len(chalk) - s := make([]int, n+1) - for i := 0; i < n; i++ { - s[i+1] = s[i] + chalk[i] + s := 0 + for _, x := range chalk { + s += x + } + k %= s + for i := 0; ; i++ { + if k < chalk[i] { + return i + } + k -= chalk[i] } - k %= s[n] - return sort.Search(n, func(i int) bool { return s[i+1] > k }) } ``` @@ -128,19 +139,36 @@ func chalkReplacer(chalk []int, k int) int { ```rust impl Solution { pub fn chalk_replacer(chalk: Vec, k: i32) -> i32 { - let pre_sum: Vec = chalk - .into_iter() - .map(|x| x as i64) - .scan(0, |state, x| { - *state += x; - Some(*state) - }) - .collect(); - - pre_sum.binary_search(&((k as i64) % pre_sum.last().unwrap())).map_or_else( - |e| e, - |v| v + 1 - ) as i32 + let mut s: i64 = chalk + .iter() + .map(|&x| x as i64) + .sum(); + let mut k = (k as i64) % s; + for (i, &x) in chalk.iter().enumerate() { + if k < (x as i64) { + return i as i32; + } + k -= x as i64; + } + 0 + } +} +``` + +### **TypeScript** + +```ts +function chalkReplacer(chalk: number[], k: number): number { + let s = 0; + for (const x of chalk) { + s += x; + } + k %= s; + for (let i = 0; ; ++i) { + if (k < chalk[i]) { + return i; + } + k -= chalk[i]; } } ``` diff --git a/solution/1800-1899/1894.Find the Student that Will Replace the Chalk/Solution.cpp b/solution/1800-1899/1894.Find the Student that Will Replace the Chalk/Solution.cpp index 1c49693d1879d..3448711b14fb8 100644 --- a/solution/1800-1899/1894.Find the Student that Will Replace the Chalk/Solution.cpp +++ b/solution/1800-1899/1894.Find the Student that Will Replace the Chalk/Solution.cpp @@ -1,10 +1,13 @@ class Solution { public: int chalkReplacer(vector& chalk, int k) { - int n = chalk.size(); - vector s(n, chalk[0]); - for (int i = 1; i < n; ++i) s[i] = s[i - 1] + chalk[i]; - k %= s[n - 1]; - return upper_bound(s.begin(), s.end(), k) - s.begin(); + long long s = accumulate(chalk.begin(), chalk.end(), 0LL); + k %= s; + for (int i = 0;; ++i) { + if (k < chalk[i]) { + return i; + } + k -= chalk[i]; + } } }; \ No newline at end of file diff --git a/solution/1800-1899/1894.Find the Student that Will Replace the Chalk/Solution.go b/solution/1800-1899/1894.Find the Student that Will Replace the Chalk/Solution.go index ce7a0de2114bc..14e167fa004ef 100644 --- a/solution/1800-1899/1894.Find the Student that Will Replace the Chalk/Solution.go +++ b/solution/1800-1899/1894.Find the Student that Will Replace the Chalk/Solution.go @@ -1,9 +1,13 @@ func chalkReplacer(chalk []int, k int) int { - n := len(chalk) - s := make([]int, n+1) - for i := 0; i < n; i++ { - s[i+1] = s[i] + chalk[i] + s := 0 + for _, x := range chalk { + s += x + } + k %= s + for i := 0; ; i++ { + if k < chalk[i] { + return i + } + k -= chalk[i] } - k %= s[n] - return sort.Search(n, func(i int) bool { return s[i+1] > k }) } \ No newline at end of file diff --git a/solution/1800-1899/1894.Find the Student that Will Replace the Chalk/Solution.java b/solution/1800-1899/1894.Find the Student that Will Replace the Chalk/Solution.java index efdf40d6d8016..6fec2a84f3602 100644 --- a/solution/1800-1899/1894.Find the Student that Will Replace the Chalk/Solution.java +++ b/solution/1800-1899/1894.Find the Student that Will Replace the Chalk/Solution.java @@ -1,21 +1,15 @@ class Solution { public int chalkReplacer(int[] chalk, int k) { - int n = chalk.length; - long[] s = new long[n + 1]; - s[0] = chalk[0]; - for (int i = 1; i < n; ++i) { - s[i] = s[i - 1] + chalk[i]; + long s = 0; + for (int x : chalk) { + s += x; } - k %= s[n - 1]; - int left = 0, right = n - 1; - while (left < right) { - int mid = (left + right) >> 1; - if (s[mid] > k) { - right = mid; - } else { - left = mid + 1; + k %= s; + for (int i = 0;; ++i) { + if (k < chalk[i]) { + return i; } + k -= chalk[i]; } - return left; } } \ No newline at end of file diff --git a/solution/1800-1899/1894.Find the Student that Will Replace the Chalk/Solution.py b/solution/1800-1899/1894.Find the Student that Will Replace the Chalk/Solution.py index 44cd704347bd7..e68cc368b5845 100644 --- a/solution/1800-1899/1894.Find the Student that Will Replace the Chalk/Solution.py +++ b/solution/1800-1899/1894.Find the Student that Will Replace the Chalk/Solution.py @@ -1,5 +1,8 @@ class Solution: def chalkReplacer(self, chalk: List[int], k: int) -> int: - s = list(accumulate(chalk)) - k %= s[-1] - return bisect_right(s, k) + s = sum(chalk) + k %= s + for i, x in enumerate(chalk): + if k < x: + return i + k -= x diff --git a/solution/1800-1899/1894.Find the Student that Will Replace the Chalk/Solution.rs b/solution/1800-1899/1894.Find the Student that Will Replace the Chalk/Solution.rs index da08095089d35..37cf29fe22368 100644 --- a/solution/1800-1899/1894.Find the Student that Will Replace the Chalk/Solution.rs +++ b/solution/1800-1899/1894.Find the Student that Will Replace the Chalk/Solution.rs @@ -1,17 +1,16 @@ impl Solution { pub fn chalk_replacer(chalk: Vec, k: i32) -> i32 { - let pre_sum: Vec = chalk - .into_iter() - .map(|x| x as i64) - .scan(0, |state, x| { - *state += x; - Some(*state) - }) - .collect(); - - pre_sum.binary_search(&((k as i64) % pre_sum.last().unwrap())).map_or_else( - |e| e, - |v| v + 1 - ) as i32 + let mut s: i64 = chalk + .iter() + .map(|&x| x as i64) + .sum(); + let mut k = (k as i64) % s; + for (i, &x) in chalk.iter().enumerate() { + if k < (x as i64) { + return i as i32; + } + k -= x as i64; + } + 0 } } diff --git a/solution/1800-1899/1894.Find the Student that Will Replace the Chalk/Solution.ts b/solution/1800-1899/1894.Find the Student that Will Replace the Chalk/Solution.ts new file mode 100644 index 0000000000000..4c4e55915d353 --- /dev/null +++ b/solution/1800-1899/1894.Find the Student that Will Replace the Chalk/Solution.ts @@ -0,0 +1,13 @@ +function chalkReplacer(chalk: number[], k: number): number { + let s = 0; + for (const x of chalk) { + s += x; + } + k %= s; + for (let i = 0; ; ++i) { + if (k < chalk[i]) { + return i; + } + k -= chalk[i]; + } +} diff --git a/solution/1800-1899/1898.Maximum Number of Removable Characters/README.md b/solution/1800-1899/1898.Maximum Number of Removable Characters/README.md index 15f1559099ee0..bf054f19c81b9 100644 --- a/solution/1800-1899/1898.Maximum Number of Removable Characters/README.md +++ b/solution/1800-1899/1898.Maximum Number of Removable Characters/README.md @@ -105,16 +105,16 @@ int search(int left, int right) { } ``` -做二分题目时,可以按照以下步骤: +做二分题目时,可以按照以下套路: -1. 写出循环条件:`while (left < right)`,注意是 `left < right`,而非 `left <= right`; -1. 循环体内,先无脑写出 `mid = (left + right) >> 1`; -1. 根据具体题目,实现 `check()` 函数(有时很简单的逻辑,可以不定义 `check`),想一下究竟要用 `right = mid`(模板 1) 还是 `left = mid`(模板 2); - - 如果 `right = mid`,那么无脑写出 else 语句 `left = mid + 1`,并且不需要更改 mid 的计算,即保持 `mid = (left + right) >> 1`; - - 如果 `left = mid`,那么无脑写出 else 语句 `right = mid - 1`,并且在 mid 计算时补充 +1,即 `mid = (left + right + 1) >> 1`。 -1. 循环结束时,left 与 right 相等。 +1. 写出循环条件 $left < right$; +1. 循环体内,不妨先写 $mid = \lfloor \frac{left + right}{2} \rfloor$; +1. 根据具体题目,实现 $check()$ 函数(有时很简单的逻辑,可以不定义 $check$),想一下究竟要用 $right = mid$(模板 $1$) 还是 $left = mid$(模板 $2$); +     - 如果 $right = mid$,那么写出 else 语句 $left = mid + 1$,并且不需要更改 mid 的计算,即保持 $mid = \lfloor \frac{left + right}{2} \rfloor$; +     - 如果 $left = mid$,那么写出 else 语句 $right = mid - 1$,并且在 $mid$ 计算时补充 +1,即 $mid = \lfloor \frac{left + right + 1}{2} \rfloor$; +1. 循环结束时,$left$ 与 $right$ 相等。 -注意,这两个模板的优点是始终保持答案位于二分区间内,二分结束条件对应的值恰好在答案所处的位置。 对于可能无解的情况,只要判断二分结束后的 left 或者 right 是否满足题意即可。 +注意,这两个模板的优点是始终保持答案位于二分区间内,二分结束条件对应的值恰好在答案所处的位置。 对于可能无解的情况,只要判断二分结束后的 $left$ 或者 $right$ 是否满足题意即可。