算法可以調度思維,讓程序員的思維發散,找到更好的解決方案。
第一題:執行指令后的得分
題目:
給你兩個數組:
instructions
和values
,數組的長度均為n
。你需要根據以下規則模擬一個過程:
從下標
i = 0
的第一個指令開始,初始得分為 0。
- 如果
instructions[i]
是add
:將values[i]
加到你的得分中。移動到下一個指令(i + 1)
- 如果
instructions[i]
是jump
:移動到下標為(i + values[i])
的指令,但不修改你的得分。當以下任一情況發生時,過程會終止:
越界(即i < 0
或i >= n
),或嘗試再次執行已經執行過的指令。被重復訪問的指令不會再次執行。返回過程結束時的得分。
思路:
遍歷一遍操作數,如果如果遇到的是
add
,就將得分加到自己的得分中。如果遇到的是jump
,那末就將循環變量自增value-1
,減 1 是因為下一次循環會增 1 ,剛好抵消。
代碼實現
class Solution {public long calculateScore(String[] instructions, int[] values) {long ans = 0;for(int i = 0;i >= 0 && i < instructions.length;i++) {if("ok".equals(instructions[i])) break;String op = instructions[i];instructions[i] = "ok";if("add".equals(op)) {ans += values[i];}if("jump".equals(op)) {i += values[i]-1;}}return ans;}
}
第二題:非遞減數組的最大長度
題目:
給你一個整數數組
nums
。在一次操作中,你可以選擇一個子數組,并將其替換為一個等于該子數組 最大值 的單個元素。返回經過零次或多次操作后,數組仍為 非遞減 的情況下,數組 可能的最大長度。子數組 是數組中一個連續、非空 的元素序列。
思路:
根據題意,假設遇到數組中的第
i
項為 a i a_i ai? 那末 a i a_i ai? 后面所有比它小的項都會被替換為 a i a_i ai? ,直到遇到下一個比它大的項,就會開啟下一輪的新的替換。比如:4 1 2 3 5 1 3,那末,第
1
項后所有比4
小的數,都會被替換為4
,直到遇到5
才會開啟下一輪新的替換,因此,樣例的答案為:2 (最后的數組為:[4,5]
)故,只需要記錄最大的前一項即可。
代碼實現
class Solution {public int maximumPossibleSize(int[] nums) {int ans = 1,t = nums[0];for(int i = 1;i < nums.length;i++)if(t <= nums[i]) {ans ++;t = nums[i];}return ans;}
}
第三題:求出數組的X值 I
題目:
給你一個由 正 整數組成的數組
nums
,以及一個 正 整數k
。你可以對nums
執行 一次 操作,該操作中可以移除任意 不重疊 的前綴和后綴,使得nums
仍然 非空 。你需要找出nums
的 x 值,即在執行操作后,剩余元素的 乘積 除以k
后的 余數 為x
的操作數量。返回一個大小為k
的數組result
,其中result[x]
表示對于0 <= x <= k - 1
,nums
的 x 值。數組的 前綴 指從數組起始位置開始到數組中任意位置的一段連續子數組。數組的 后綴 是指從數組中任意位置開始到數組末尾的一段連續子數組。子數組 是數組中一段連續的元素序列。注意,在操作中選擇的前綴和后綴可以是 空的 。
思路:
題目的意思其實就是找到一個子數組,使得子數組的乘積模
k
的每種情況的數量。可以設置f[i ,j]
表示以第i
項結尾的所有模k
結果為j
的所有子數組。因此,考慮f[i-1 , j]
項,設f[i,p]
項是f[i-1, j]
項轉移而來的,因此j
是前i-1
項模k
的結果,故,當包含第i
項時,
j = ■ % k,此時,算上最后一項,p = (nums_i * ■) % k = (nums_i % k * ■ % k) % k = j * (nums_i % k) % k
因此,轉移方程為:
f[i,j * (nums_i % k) % k] += f[i-1, j]
最后,考慮剛開始時,
f[i,nums_i % k] = 1
必定有一個。
代碼實現
public class Solution {public long[] resultArray(int[] nums, int k) {long[] ans = new long[k];int[][] f = new int[nums.length+1][k];for(int i = 1;i < f.length;i++) {f[i][nums[i-1] % k] = 1;for(int j = 0;j < k;j++) {f[i][j * (nums[i-1] % k) % k] += f[i-1][j];}}// 最后只需要統計一遍即可for(int i = 1;i < f.length;i++) {for(int j = 0;j < k;j++) {ans[j] += f[i][j];}}return ans;}
}
第四題:求出數組的X值 II
這題對于我現有的情況來說,已經很難了,因此,只能通過80% ~ 90%,搜到的題解有些難以理解,等我后期再理解理解
題目:
給你一個由 正 整數組成的數組
nums
,以及一個 正 整數k
。你可以對nums
執行 一次 操作,該操作中可以移除任意 不重疊 的前綴和后綴,使得nums
仍然 非空 。你需要找出nums
的 x 值,即在執行操作后,剩余元素的 乘積 除以k
后的 余數 為x
的操作數量。返回一個大小為k
的數組result
,其中result[x]
表示對于0 <= x <= k - 1
,nums
的 x 值。數組的 前綴 指從數組起始位置開始到數組中任意位置的一段連續子數組。數組的 后綴 是指從數組中任意位置開始到數組末尾的一段連續子數組。子數組 是數組中一段連續的元素序列。注意,在操作中選擇的前綴和后綴可以是 空的 。
思路:
題目的意思實際就是,每次給一個下標(
index
) 和 替換的值(value
),每次將數組中的下標為index
的位置替換為value
,之后,給定一個起始下標(start
) 和 值(x
),找到從start
開始,直到數組的末尾的所有前綴的乘積模k
的值為x
的前綴的個數,因此我直接通過暴力解法沒有全對。
算法實現
class Solution {public int[] resultArray(int[] nums, int k, int[][] queries) {int[] ans = new int[queries.length];for(int i = 0;i < queries.length;i++) {int index = queries[i][0];int value = queries[i][1];int start = queries[i][2];int x = queries[i][3];nums[index] = value;long res = 1;int ans_t = 0;for(int j = start;j < nums.length;j++) {res = res * nums[j] % k;if(res % k == x) ans_t ++;}ans[i] = ans_t;}return ans;}
}