挺简单的
给你一个整数数组 arr
,以及 a
、b
、c
三个整数。请你统计其中好三元组的数量。
如果三元组 (arr[i], arr[j], arr[k])
满足下列全部条件,则认为它是一个 好三元组 。
其中 |x| 表示 x 的绝对值。
返回 好三元组的数量 。
示例 1
输入:arr = [3,0,1,1,9,7], a = 7, b = 2, c = 3
输出:4
解释:一共有 4 个好三元组:[(3,0,1), (3,0,1), (3,1,1), (0,1,1)] 。
示例 2
输入:arr = [1,1,2,2,3], a = 0, b = 0, c = 1
输出:0
解释:不存在满足所有条件的三元组。
提示
直接三个for模拟就完事了 没怎么想
大概可以想一下这三个条件存在什么性质 只枚举j和k
暴力O(n^3)能过就完了
class Solution {
public:
int countGoodTriplets(vector<int>& arr, int a, int b, int c) {
int ans=0;
int n=arr.size();
for(int i=0;i<n-2;i++)
for(int j=i+1;j<n-1;j++)
for(int k=j+1;k<n;k++)
if(abs(arr[i]-arr[j])<=a&&abs(arr[j]-arr[k])<=b&&abs(arr[i]-arr[k])<=c)ans++;
return ans;
}
};
给你一个由 不同 整数组成的整数数组 arr 和一个整数 k 。
每回合游戏都在数组的前两个元素(即 arr[0] 和 arr[1] )之间进行。比较 arr[0] 与 arr[1] 的大小,较大的整数将会取得这一回合的胜利并保留在位置 0 ,较小的整数移至数组的末尾。当一个整数赢得 k 个连续回合时,游戏结束,该整数就是比赛的 赢家 。
返回赢得比赛的整数。
题目数据 保证 游戏存在赢家。
示例 1
输入:arr = [2,1,3,5,4,6,7], k = 2
输出:5
解释:一起看一下本场游戏每回合的情况:
因此将进行 4 回合比赛,其中 5 是赢家,因为它连胜 2 回合。
示例 2
输入:arr = [3,2,1], k = 10
输出:3
解释:3 将会在前 10 个回合中连续获胜。
示例 3
输入:arr = [1,9,8,2,3,7,6,4,5], k = 7
输出:9
示例 4
输入:arr = [1,11,22,33,44,55,66,77,88,99], k = 1000000000
输出:99
提示
首先我看到了1e9的k 就感觉是不是要用公式来做
1e5的规模大概率要用线性的
后来分析了下得出直接模拟就能做了
因为 当k>n的时候 赢的那个数肯定是最大的那个数
简单证明下 因为如果是其他数 他必定会遇到最大那个数 因为其他数都放在了后面
那么模拟就很简单了 用deque双端队列就能O(1)操作两端的 当然手写个链表也行
代码写了点注释
总的复杂度是O(n)的
class Solution {
public:
int getWinner(vector<int>& arr, int k) {
if(k>=arr.size())return *max_element(arr.begin(),arr.end()); //直接返回
deque<int> dq; //双端队列模拟
for(auto i:arr)dq.push_back(i);
int win=0,a,b;
while(win<k){ //这个while最多会2k的复杂度
a=dq.front(); //第一个
dq.pop_front();
b=dq.front(); //第二个
if(a>b){ //第一个赢
dq.pop_front();
dq.push_front(a);
dq.push_back(b);
win++;
}
else{
dq.push_back(a); //其实小的没有必要放在后面 因为必赢
win=1;
}
}
return max(a,b); //有可能第一次就第二个赢
}
};
给你一个 n x n 的二进制网格 grid,每一次操作中,你可以选择网格的 相邻两行 进行交换。
一个符合要求的网格需要满足主对角线以上的格子全部都是 0 。
请你返回使网格满足要求的最少操作次数,如果无法使网格符合要求,请你返回 -1 。
主对角线指的是从 (1, 1) 到 (n, n) 的这些格子。
示例 1
输入:grid = [[0,0,1],[1,1,0],[1,0,0]]
输出:3
示例 2
输入:grid = [[0,1,1,0],[0,1,1,0],[0,1,1,0],[0,1,1,0]]
输出:-1
解释:所有行都是一样的,交换相邻行无法使网格符合要求。
示例 3
输入:grid = [[1,0,0],[1,1,0],[1,1,1]]
输出:0
提示
这种最少步数的 必须得先想清楚怎么才是最少的
首先要先想出目标位置是哪里:
后缀0从上到下依次是n-1~0 然后这个后缀0是可以多的
比如说4*4矩阵
中后缀0从上到下可以是3310 不必要是3210
那么就要想到的就是一个贪心 如果是符合后缀0的长度的话 肯定是越近越好(交换最少) 所以就要根据目标距离和长度是否符合 来进行贪心
然后还有一个要想是如何交换才是最少次数 我的想法就是
像冒泡排序一样 不断向上把最上面的位置固定
简单证明下就是 这样子交换每次交换都是关键交换 不存在交换来又交换回去的多余交换 这样子就能保证最上面的位置都是必要的
流程:
复杂度为O(n^2) 因为模拟了交换时候的其他位置会被挤向下
这个其实可以用区间结构给优化掉
但是优化没有啥意义 因为遍历矩阵就已经要平方了
class Solution {
public:
int minSwaps(vector<vector<int>>& grid) {
int n=grid.size();
vector<int> idx(n,-1),zero(n,0);
for(int row=0;row<n;row++) //先记录下后缀0的个数
for(int col=n-1;col>=1;col--)
if(!grid[row][col])zero[row]++;
else break;
for(int row=0;row<n;row++) //处理下idx
if(idx[zero[row]]==-1)idx[zero[row]]=row;
else{
int j=zero[row];
while(j&&idx[j]!=-1)j--; //不断跳位置
idx[j]=row;
}
int ans=0;
int pos=0;
for(int i=n-1;i>=1;i--) //不可能
if(idx[i]==-1)return -1;
for(int i=n-1;i>=1;i--){ //算一下交换的距离
ans+=idx[i]-pos;
for(int j=0;j<n;j++)if(idx[j]<idx[i])idx[j]++;
pos++;
}
return ans;
}
};
你有两个 有序 且数组内元素互不相同的数组 nums1 和 nums2 。
一条 合法路径 定义如下:
得分定义为合法路径中不同数字的和。
请你返回所有可能合法路径中的最大得分。
由于答案可能很大,请你将它对 10^9 + 7 取余后返回。
示例 1
输入:nums1 = [2,4,5,8,10], nums2 = [4,6,8,9]
输出:30
解释:合法路径包括:
[2,4,5,8,10], [2,4,5,8,9], [2,4,6,8,9], [2,4,6,8,10],(从 nums1 开始遍历)
[4,6,8,9], [4,5,8,10], [4,5,8,9], [4,6,8,10] (从 nums2 开始遍历)
最大得分为上图中的绿色路径 [2,4,6,8,10] 。
示例 2
输入:nums1 = [1,3,5,7,9], nums2 = [3,5,100]
输出:109
解释:最大得分由路径 [1,3,5,100] 得到。
示例 3
输入:nums1 = [1,2,3,4,5], nums2 = [6,7,8,9,10]
输出:40
解释:nums1 和 nums2 之间无相同数字。
最大得分由路径 [6,7,8,9,10] 得到。
示例 4
输入:nums1 = [1,4,5,8,9,11,19], nums2 = [2,3,4,11,12]
输出:61
提示
这个只要求最大得分 不管路径如何 那么第一想法就是动态规划dp了
比大小我原来还想着那个求余怎么比 后来发现数据最多是1e12 开个long long绝对够了
那么直接可以得出转移方程
如果两个数组不一样的话 那么就只能加上前面的
如果两个数组一样的 那么就都变成大的 这样子就能换路了
处理的时候要注意下
dp需要根据两个数组的进度进行dp 因为相同数字时候会遇到用到另一个dp数组的
所以必须要两边同步进行
因为是严格单调增的 所以可以双指针同步进行
如果不是的话 就得用hashmap预处理出一样的位置在哪
总的时间复杂度是O(n)的
class Solution {
public:
int maxSum(vector<int>& nums1, vector<int>& nums2) {
vector<unsigned long long> dp1(nums1.size(),0),dp2(nums2.size(),0);
int i=0,j=0;
bool flag; //flag为true表示第一个数组动 否则第二个数组
if(nums1[0]<=nums2[0])flag=true; //小的先手
else flag=false;
dp1[0]=nums1[0]; //设置下初始值
dp2[0]=nums2[0]; //当然是有第一个数就一样的特殊情况
while(i<nums1.size()&&j<nums2.size())
{
if(flag){
if(nums1[i]==nums2[j]){
dp1[i]=max((i>0?dp1[i-1]:0)+nums1[i],dp2[j]);
dp2[j]=max(dp1[i],dp2[j]); //有点多余 为了处理特殊情况
}
else dp1[i]=(i>0?dp1[i-1]:0)+nums1[i];
}
else{
if(nums1[i]==nums2[j]){
dp2[j]=max((j>0?dp2[j-1]:0)+nums2[j],dp1[i]);
dp1[i]=max(dp1[i],dp2[j]); //有点多余 为了处理特殊情况
}
else dp2[j]=(j>0?dp2[j-1]:0)+nums2[j];
}
if(nums1[i]<=nums2[j]){ //双指针 小的动
i++;
flag=true;
}
else{
j++;
flag=false;
}
}
//处理下剩下的
while(++i<nums1.size())dp1[i]=dp1[i-1]+nums1[i];
while(++j<nums2.size())dp2[j]=dp2[j-1]+nums2[j];
return max(dp1.back(),dp2.back())%int(1e9+7);
}
};