每日算法刷题Day36 6.23:leetcode枚举技巧枚举中间4道题,用时1h30min
3. 1930.长度为3的不同回文子序列(中等,学习字符串枚举26个小写字母)
1930. 长度为 3 的不同回文子序列 - 力扣(LeetCode)
思想
1.给你一个字符串 s
,返回 s
中 长度为 3 的不同回文子序列 的个数。
即便存在多种方法来构建相同的子序列,但相同的子序列只计数一次。
回文 是正着读和反着读一样的字符串。
子序列 是由原字符串删除其中部分字符(也可以不删除)且不改变剩余字符之间相对顺序形成的一个新字符串。
- 例如,
"ace"
是"**_a_**b**_c_**d**_e_**"
的一个子序列。 s
仅由小写英文字母组成
2.此题是要维护i和k的26个字符的数量,所以都要开长度为26的数组,且枚举j中的第2层枚举26个字母,用map<int, set<int>> mp;
记录答案,更巧妙的要用位运算,暂时先不考虑
代码
c++:
class Solution {
public:int countPalindromicSubsequence(string s) {int n = s.size();vector<int> suf(26, 0);vector<int> pre(26, 0);for (int i = 1; i < n; ++i)++suf[s[i] - 'a'];++pre[s[0] - 'a'];map<int, set<int>> mp; // 中间字符-两侧字符for (int j = 1; j + 1 < n; ++j) {--suf[s[j] - 'a'];// 枚举26个字母for (int t = 0; t < 26; ++t) {if (pre[t] > 0 && suf[t] > 0) {mp[s[j] - 'a'].insert(t);}}++pre[s[j] - 'a'];}int res = 0;for (auto x : mp)res += x.second.size();return res;}
};
4. 3128.直角三角形(中等)
3128. 直角三角形 - 力扣(LeetCode)
思想
1.给你一个二维 boolean 矩阵 grid
。
如果 grid
的 3 个元素的集合中,一个元素与另一个元素在 同一行,并且与第三个元素在 同一列,则该集合是一个 直角三角形。3 个元素 不必 彼此相邻。
请你返回使用 grid
中的 3 个元素可以构建的 直角三角形 数目,且满足 3 个元素值 都 为 1 。
2.我的想法就是提前算出来(i,j)
左侧,右侧,上侧和下侧1的数量,然后利用乘法原理计算,但是我一开始只考虑了右侧,没考虑左侧,所以四侧都考虑的话就直接算这一行有rowCnt个1,这一列有colCnt个1,然后乘法原理加上(rowCnt-1)*(colCnt-1)
即可,这种都是要包括(i,j)元素的,我原来的想法不包括,太复杂了
代码
c++:
我的代码:
class Solution {
public:long long numberOfRightTriangles(vector<vector<int>>& grid) {int n = grid.size(), m = grid[0].size();vector<vector<int>> rightCnt(n, vector<int>(m, 0));vector<vector<int>> leftCnt(n, vector<int>(m, 0));vector<vector<int>> upCnt(n, vector<int>(m, 0));vector<vector<int>> downCnt(n, vector<int>(m, 0));for (int i = 0; i < n; ++i) {for (int j = 1; j < m; ++j) {leftCnt[i][j] =leftCnt[i][j - 1] + (grid[i][j - 1] == 1 ? 1 : 0);}}for (int i = 0; i < n; ++i) {for (int j = m - 2; j >= 0; --j) {rightCnt[i][j] =rightCnt[i][j + 1] + (grid[i][j + 1] == 1 ? 1 : 0);}}for (int j = 0; j < m; ++j) {for (int i = 1; i < n; ++i) {upCnt[i][j] = upCnt[i - 1][j] + (grid[i - 1][j] == 1 ? 1 : 0);}}for (int j = 0; j < m; ++j) {for (int i = n - 2; i >= 0; --i) {downCnt[i][j] =downCnt[i + 1][j] + (grid[i + 1][j] == 1 ? 1 : 0);}}long long res = 0;for (int i = 0; i < n; ++i) {for (int j = 0; j < m; ++j) {if (grid[i][j] == 0)continue;res += 1LL * rightCnt[i][j] * upCnt[i][j] +1LL * rightCnt[i][j] * downCnt[i][j] +1LL * leftCnt[i][j] * upCnt[i][j] +1LL * leftCnt[i][j] * downCnt[i][j];}}return res;}
};
优化:
class Solution {
public:long long numberOfRightTriangles(vector<vector<int>>& grid) {int n = grid.size(), m = grid[0].size();vector<int> rowCnt(n, 0); // 每行1个数vector<int> colCnt(m, 0); // 每列1个数for (int i = 0; i < n; ++i) {for (int j = 0; j < m; ++j) {if (grid[i][j] == 1) {++rowCnt[i];++colCnt[j];}}}long long res = 0;for (int i = 0; i < n; ++i) {for (int j = 0; j < m; ++j) {if (grid[i][j] == 0)continue;res += 1LL * (rowCnt[i] - 1) * (colCnt[j] - 1);}}return res;}
};
5. 2874.有序三元组中的最大值II(中等)
2874. 有序三元组中的最大值 II - 力扣(LeetCode)
思想
1.给你一个下标从 0 开始的整数数组 nums
。
请你从所有满足 i < j < k
的下标三元组 (i, j, k)
中,找出并返回下标三元组的最大值。如果所有满足条件的三元组的值都是负数,则返回 0
。
下标三元组 (i, j, k)
的值等于 (nums[i] - nums[j]) * nums[k]
。
2.要让(nums[i] - nums[j]) * nums[k]
最大,对于固定的nums[j]
,即让nums[i]
和nums[k]
最大,所以要得到最大前缀和后缀,最大前缀单变量维护即可,最大后缀数组在枚举j前得到
代码
c++:
class Solution {
public:long long maximumTripletValue(vector<int>& nums) {int n=nums.size();vector<int> suf(n,0);suf[n-1]=nums[n-1];for(int i=n-2;i>=0;--i) suf[i]=max(suf[i+1],nums[i]);int pre=nums[0];long long res=0;for(int j=1;j+1<n;++j){if(pre>nums[j] && suf[j+1]>0) res=max(res,1LL*(pre-nums[j])*suf[j+1]);pre=max(pre,nums[j]);}return res;}
};
6. 447.回旋镖的数量(中等)
447. 回旋镖的数量 - 力扣(LeetCode)
思想
1.给定平面上 n
对 互不相同 的点 points
,其中 points[i] = [xi, yi]
。回旋镖 是由点 (i, j, k)
表示的元组 ,其中 i
和 j
之间的欧式距离和 i
和 k
之间的欧式距离相等(需要考虑元组的顺序)。
返回平面上所有回旋镖的数量。
2.分析题目,i与j可k无关,j和k顺序可以调换,所以两个枚举可以通过一层枚举+变量维护实现。所以第一层枚举i,通过map<long long, int> mp
记录距离出现的次数,然后第二层枚举j,直接利用之前学习的有序对个数计算方法res += mp[t]++;
,然后最后答案乘个2
代码
c++:
class Solution {
public:int numberOfBoomerangs(vector<vector<int>>& points) {int n = points.size();if (n < 3)return 0;int res = 0;for (int i = 0; i < n; ++i) {map<long long, int> mp; // 距离-个数for (int j = 0; j < n; ++j) {if (j == i)continue;long long t = (points[i][0] - points[j][0])*(points[i][0] - points[j][0]) +(points[i][1] - points[j][1])*(points[i][1] - points[j][1]);res += mp[t]++;}}return res * 2;}
};