在經歷了198周、199周連續的兩道題全退,1000+、2000+排名之後終於迎來了新一輪的手速競賽。可以看到本週題相對來說非常簡單,前489名都是AK了四道題的選手。自己的成績也還算過的去,勉強擠進了前150名,得益於當天良好的狀態和清晰的思路。。。
題目內容:https://leetcode-cn.com/contest/weekly-contest-200/problems/count-good-triplets/
思路:
看了一下總共的數據量不大,所以直接選擇暴力O(N ^ 3)的時間複雜度去進行求解。
解題程式碼:
class Solution {
public int countGoodTriplets(int[] arr, int a, int b, int c) {
int l = arr.length;
int cnt = 0;
for(int i=0; i<l-2; i++) {
for(int j=i+1; j<l-1;j++) {
for(int k =j+1; k<l;k++) {
if(abs(arr[j]-arr[i])<=a && abs(arr[k]-arr[j])<=b&&abs(arr[k]-arr[i])<=c) {
cnt++;
}
}
}
}
return cnt;
}
private int abs(int i) {
if(i<0) {
return -i;
}
return i;
}
}
題目內容:https://leetcode-cn.com/contest/weekly-contest-200/problems/find-the-winner-of-an-array-game/
思路:
這道題題目很友好的告訴我們一定存在遊戲的贏家,同時也說了讓我們去尋找第一個符合的整數即可。我們可以先簡單分析一下存在哪些情況:
1 最常規的情況:arr = [2, 1, 3, 5, 4, 6, 7], k =2。k < arr.length,arr.length - target的index > k - 1,不需要target回圈的去和已經參與過比較的元素再去比較。
先看第一個元素2, 2比1大,第一次比較之後arr = [2, 3, 5, 4 ,6, 7, 1],2再去和3比會輸掉,但這次比較的結果同時導致了3獲得了一次勝利,這時arr = [3, 5, 4, 6, 7, 1, 2],3比5小,這次比較3又回輸掉,但這次比較之後5留了下來並且積攢了一個勝場,5再去和4比,獲勝,這時我們得到了最終的目標結果:5。
這種場景我們只需要從頭尋找比他上一個數大的元素,再向後尋找k-1個元素看看是不是當前元素逗比他們大,同時注意處理第一個元素的情況,第一個元素需要向後去尋找k個元素看看是不是都比他們大
2 情況1的變體,k < arr.length, arr.length - target的index < k - 1的場景,這種場景下我們可以確定,如果k在這次比較中獲勝,那麼k一定是比所有從隊首比較輸了進入隊尾的元素大,所以k只要比它到隊尾的所有元素大即可,舉例就是 arr = [2, 3, 4, 9, 8], k=3。具體比較路徑大家可以在演算紙上自行推導。
3 特殊情況:當有 k > arr.length的時候,因爲陣列一定存在贏家,所以這個贏家一定是全陣列最大的元素,只需要找陣列最大元素即可。
解題程式碼:
class Solution {
public int getWinner(int[] arr, int k) {
int n = arr.length;
if(k>=n) {
return findMax(arr);
}
int max = Integer.MIN_VALUE;
for(int i=0; i<n; i++) {
if(arr[i] > max) {
max = arr[i];
int l = i==0? k:k-1;
if(higher(arr, i , l)) {
return arr[i];
}
}
}
return 0;
}
private boolean higher(int[] arr, int idx, int l) {
int max = idx+l+1 > arr.length? arr.length: idx+l+1;
for(int i=idx+1; i<max; i++) {
if(arr[idx] < arr[i]) {
return false;
}
}
return true;
}
private int findMax(int[] arr) {
int max = Integer.MIN_VALUE;
for(int a:arr) {
if(a > max) {
max = a;
}
}
return max;
}
}
題目內容:https://leetcode-cn.com/contest/weekly-contest-200/problems/minimum-swaps-to-arrange-a-binary-grid/
思路:
我們可以利用抽象思維,把二維陣列轉化爲一維陣列,抽象的依據是我們要看對角線右上的元素,所以我們關心的就是每一行最後一個非0元素的位置,相應的,例子中的grid = [[0,0,1],[1,1,0],[1,0,0]]就可以抽象成arr=[2,1,0]。得到了抽象陣列之後,我們只需要讓抽象陣列滿足arr[i] <=i即可。我們從i到n-1的位置,每次尋找從i之後第一個滿足arr[p] <= i位置的元素,將p逐漸交換到i的位置並記錄交換次數 p - i,然後得到交換之後的新陣列arr,重複這個過程直到所有的i都滿足arr[i] <= i。有一種特殊的場景是沒有解,即存在位置i,在其之後的所有p點都不存在arr[p] <= i,這種情況下只需要直接返回-1即可。
以grid = [[0,0,1],[1,1,0],[1,0,0]]爲例我們分析演算法過程:
解題程式碼:
class Solution {
public int minSwaps(int[][] grid) {
int n = grid.length;
int res = 0;
int[] idx = new int[n];
for (int i = 0; i < n; i++) {
idx[i] = lastP(grid[i]);
}
for (int i = 0; i < n; i++) {
int firstI = findFirst(idx, i);
//non suit
if (firstI == -1) {
return -1;
}
res += firstI - i;
// System.out.println("res = " +res);
swapTo(idx, firstI, i);
}
return res;
}
private void swapTo(int[] before, int lastP, int startP) {
int tmp = before[lastP];
for(int i=lastP;i>startP;i--) {
before[i] = before[i-1];
}
before[startP] = tmp;
}
private int findFirst(int[] arr, int target) {
for(int i=target; i<arr.length; i++) {
if(arr[i] <= target) {
return i;
}
}
return -1;
}
private int lastP(int[] arr) {
for(int i=arr.length-1; i >=0; i--) {
if(arr[i] == 1) {
return i;
}
}
return 0;
}
}
題目內容:https://leetcode-cn.com/contest/weekly-contest-200/problems/get-the-maximum-score/
思路:
我不知道這道題爲啥能被稱之爲Hard。。。思路很簡單,可以簡易的理解爲陣列對其問題我們一起過一遍題目範例1,按照相同元素在一起進行對其,如果沒有元素就用x來表示,通過LinkedList或者ArrayList進行儲存,同時區間內部可以求和。
題目:
Nums1 2 - 4 - 5 - 8 - 10
Nums2 4 - 6 - 8 - 9
對齊區間求和之後:
2 - 4 - 5 - 8 - 10
0 - 4 - 6 - 8 - 9
所有對齊分割點元素都可以作爲跳躍點,所以我們只需要利用兩個list分別儲存對齊之後的區間和,每次從兩個list的區間裏面選最大的即可,即最終選擇的結果是2 - 4 -6 - 8 -10同時要注意處理末尾的場景,不要丟失數據。在求和的過程中記得實時取模防止溢位異常。
解題程式碼:
class Solution {
public int maxSum(int[] nums1, int[] nums2) {
int modNumber = 1000000000 + 7;
List<Integer> router = new ArrayList<>();
List<Long> part1 = new ArrayList<>();
List<Long> part2 = new ArrayList<>();
long l1 = 0l;
long l2 = 0l;
long res = 0l;
int i=0;
int j=0;
while(i<nums1.length && j<nums2.length) {
if(nums1[i] == nums2[j]) {
part1.add(l1);
part2.add(l2);
router.add(nums1[i]);
// re-init
l1=0l;
l2=0l;
i++;
j++;
} else {
if(nums1[i]>nums2[j]) {
l2+=nums2[j];
j++;
} else {
l1+=nums1[i];
i++;
}
}
}
while(i<nums1.length) {
l1+=nums1[i];
i++;
}
while(j<nums2.length) {
l2+=nums2[j];
j++;
}
part1.add(l1);
part2.add(l2);
for(int idx=0;idx<part1.size(); idx++) {
res = (Math.max(part1.get(idx), part2.get(idx)) + res)% modNumber;
}
for(int k=0; k<router.size();k++) {
res = (router.get(k) + res) % modNumber;
}
return (int)res % modNumber;
}
}