杂题部分
- 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;elsecur++;}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;}};