雜題部分
- 3131. 找出與陣列相加的整數 I
思路
快排+直接找差值。
void quickSort(int *arr,int low,int high)
{
if(high<=low) return;
int i=low;
int j=high;
int pivot=arr[low];
while(1)
{
// 1. 自左到右搜尋,直到比pivot大後停止。
while(arr[i]<=pivot)
{
i++;
if(i==high) break;
}
// 2. 自右到左搜尋,直到比pivot小後停止。
while(arr[j]>=pivot)
{
j--;
if(j==low) break;
}
// 3. 兩個指標相遇時或跨越後,停止。
if(i>=j) break;
// 4.交換兩個指標的值。
int temp=arr[i];
arr[i]=arr[j];
arr[j]=temp;
}
// 交換pivot與右指標的值
arr[low]=arr[j];
arr[j]=pivot;
// 分段進行快排
quickSort(arr,low,j-1);
quickSort(arr,j+1,high);
}
int addedInteger(int* nums1, int nums1Size, int* nums2, int nums2Size) {
quickSort(nums1,0,nums1Size-1);
quickSort(nums2,0,nums2Size-1);
return nums2[0]-nums1[0];
}
- 3132. 找出與陣列相加的整數 II
void quickSort(int *arr,int low,int high)
{
if(high<=low) return;
int i=low;
int j=high;
int pivot=arr[low];
while(1)
{
// 1. 自左到右搜尋,直到比pivot大後停止。
while(arr[i]<=pivot)
{
i++;
if(i==high) break;
}
// 2. 自右到左搜尋,直到比pivot小後停止。
while(arr[j]>=pivot)
{
j--;
if(j==low) break;
}
// 3. 兩個指標相遇時或跨越後,停止。
if(i>=j) break;
// 4.交換兩個指標的值。
int temp=arr[i];
arr[i]=arr[j];
arr[j]=temp;
}
// 交換pivot與右指標的值
arr[low]=arr[j];
arr[j]=pivot;
// 分段進行快排
quickSort(arr,low,j-1);
quickSort(arr,j+1,high);
}
int minimumAddedInteger(int* nums1, int nums1Size, int* nums2, int nums2Size) {
quickSort(nums1,0,nums1Size-1);
quickSort(nums2,0,nums2Size-1);
for(int i=2;i>=0;i--)
{
int left=i+1,right=1;
while(left<nums1Size && right < nums2Size)
{
if(nums1[left]-nums2[right]==nums1[i]-nums2[0])
right++;
left++;
}
if(right==nums2Size)
return nums2[0]-nums1[i];
}
return 0;
}
- 3148. 矩陣中的最大得分
思路
方法一:動態規劃
思路與演算法
記 \(f(i,j)\) 表示以矩陣 \(grid\) 中位置 \((i,j)\) 結束的最大得分。由於每一步只能往右走或者往下走,因此在進行狀態轉移時,我們分別列舉這兩種情況:
對於往右走,我們有:
這裡的 \(\max\{f(i,k),0\}\) 是由於題目要求「必須至少移動一次」,所以 \(f(i,k)\) 中並不包含「以 \((i,k)\) 同時為起點和終點」的情況,需要增加 0 來表示這一情況,才能讓狀態轉移中包含「以 \((i,k)\) 為起點,\((i,j)\) 為終點」的情況。
就算不考慮往右走的情況,上述狀態轉移方程的時間複雜度也達到了 \(O(mn)×O(n)=O(mn^2)\),會超出時間限制,因此需要進行最佳化。
注意到 \(grid(i,j)\) 與 \(k\) 無關,我們可以將其從 \(max\) 中提出:
記\(prerow(i,j)=\max\limits_{0\leqslant k<j}\{\max\{dp(i,j),0\}-grid(i,k)\}\),那麼可以使用字首和的思想,在計算完 \(f(i,j)\) 後用 \(O(1)\) 的時間得到它的值:
此時狀態轉移方程變為簡單的遞推:
同理,對於往左走,我們有:
這裡 \(precol(i,j)\) 是與 \(prerow(i,j)\) 類似的列的字首最大值。當所有的 \(dp(i,j)\) 都計算完成後,其中的最大值即為最終的答案。
題解
int maxScore(int** grid, int gridSize, int* gridColSize) {
// dp 2-dimensional matrix.
int **dp=(int**)malloc(sizeof(int*)*gridSize);
int **preRow=(int**)malloc(sizeof(int*)*gridSize);
int **preCol=(int**)malloc(sizeof(int*)*gridSize);
for(int i=0;i<gridSize;i++)
{
dp[i]=(int*)malloc(sizeof(int)*gridColSize[i]);
preRow[i]=(int*)malloc(sizeof(int)*gridColSize[i]);
preCol[i]=(int*)malloc(sizeof(int)*gridColSize[i]);
for(int j=0;j<gridColSize[i];j++)
{
dp[i][j]=-1e8;
preRow[i][j]=0;
preCol[i][j]=0;
}
}
int ans=-1e8;
for(int i=0;i<gridSize;i++)
{
for(int j=0;j<gridColSize[i];j++)
{
if(i>0)
dp[i][j]=dp[i][j]>grid[i][j]+preCol[i-1][j]?dp[i][j]:preCol[i-1][j]+grid[i][j];
if(j>0)
dp[i][j]=dp[i][j]>grid[i][j]+preRow[i][j-1]?dp[i][j]:grid[i][j]+preRow[i][j-1];
ans=ans>dp[i][j]?ans:dp[i][j];
preRow[i][j]=preCol[i][j]=(dp[i][j]>0?dp[i][j]:0)-grid[i][j];
if(i>0)
preCol[i][j]=preCol[i][j]>preCol[i-1][j]?preCol[i][j]:preCol[i-1][j];
if(j>0)
preRow[i][j]=preRow[i][j]>preRow[i][j-1]?preRow[i][j]:preRow[i][j-1];
}
}
return ans;
}
- 2552.統計四元上升陣列
class Solution {
public:
long long countQuadruplets(vector<int>& nums) {
int n=nums.size();
vector<int> pre(n+1);
long long ans=0,cur=0;
for(int j=0;j<n;j++)
{
cur=0;
for(int k=n-1;k>j;k--) // 從後往前進行列舉
{
if(nums[j]>nums[k])
ans += (long long)(pre[nums[k]])*cur;
else
cur++;
}
for (int x=nums[j]+1;x<=n;x++)
pre[x]++; // 統計從0到j-1的小於x的數
}
return ans;
}
};
- 2306. 公司命名
思路(Hash set)
將每一個字元以首字母為key,去掉首字母為字尾儲存在hashset中。這樣我們就有
a: str1,str2,str3...
b: str1,str2,str3...
然後我們觀察是否有重複的字尾。有則去掉。這樣就有了
ans+=(a-repeat)*(b-repeat)
作為最終結果。
Code
class Solution {
public:
int get_size(unordered_set<string> &a, unordered_set<string> &b)
{
// Count for the intersected suffix.
int ans=0;
for(const string &s:a)
{
if(b.count(s))
ans++;
}
return ans;
}
long long distinctNames(vector<string>& ideas) {
unordered_map<char, unordered_set<string> > names; // Hash set put all the names with the same first letter together.
for (string &idea:ideas)
{
names[idea[0]].insert(idea.substr(1,idea.size()-1));
}
long long ans=0;
// Check for intersects and count.
for(auto [key1,val1]:names)
{
for(auto [key2,val2]:names)
{
if(key1==key2) continue;
int intersections=get_size(val1,val2);
ans+=static_cast<long long> (val1.size()-intersections)*(val2.size()-intersections);
}
}
return ans;
}
};