给你一个数组 nums ,数组中有 2n 个元素,按 [x1,x2,…,xn,y1,y2,…,yn] 的格式排列。
请你将数组按 [x1,y1,x2,y2,…,xn,yn] 格式重新排列,返回重排后的数组。
示例 1
输入:nums = [2,5,1,3,4,7], n = 3
输出:[2,3,5,4,1,7]
解释:由于 x1=2, x2=5, x3=1, y1=3, y2=4, y3=7 ,所以答案为 [2,3,5,4,1,7]
示例 2
输入:nums = [1,2,3,4,4,3,2,1], n = 4
输出:[1,4,2,3,3,2,4,1]
示例 3
输入:nums = [1,1,2,2], n = 2
输出:[1,2,1,2]
提示
- 1 <= n <= 500
很明显我们可以直接通过公式得知xi和yi的位置在哪的
xi=i yi=i+n
所以直接按i的顺序把xi yi依次push进去就行了
总的时间复杂度为O(n)
class Solution {
public:
vector<int> shuffle(vector<int>& nums, int n) {
vector<int> ans;
for(int i=0;i<n;i++)
{
ans.push_back(nums[i]); //xi
ans.push_back(nums[i+n]); //yi
}
return ans;
}
};
给你一个整数数组 arr 和一个整数 k 。
设 m 为数组的中位数,只要满足下述两个前提之一,就可以判定 arr[i] 的值比 arr[j] 的值更强:
请返回由数组中最强的 k 个值组成的列表。答案可以以 任意顺序 返回。
中位数 是一个有序整数列表中处于中间位置的值。形式上,如果列表的长度为 n ,那么中位数就是该有序列表(下标从 0 开始)中位于 ((n - 1) / 2) 的元素。
示例 1
输入:arr = [1,2,3,4,5], k = 2
输出:[5,1]
解释:中位数为 3,按从强到弱顺序排序后,数组变为 [5,1,4,2,3]。最强的两个元素是 [5, 1]。[1, 5] 也是正确答案。
注意,尽管 |5 - 3| == |1 - 3| ,但是 5 比 1 更强,因为 5 > 1 。
示例 2
输入:arr = [1,1,3,5,5], k = 2
输出:[5,5]
解释:中位数为 3, 按从强到弱顺序排序后,数组变为 [5,5,1,1,3]。最强的两个元素是 [5, 5]。
示例 3
输入:arr = [6,7,11,7,6,8], k = 5
输出:[11,8,6,6,7]
解释:中位数为 7, 按从强到弱顺序排序后,数组变为 [11,8,6,6,7,7]。
[11,8,6,6,7] 的任何排列都是正确答案。
示例 4
输入:arr = [6,-3,7,2,11], k = 3
输出:[-3,11,2]
示例 5
输入:arr = [-7,22,17,3], k = 2
输出:[22,17]
提示
- 1 <= arr.length <= 10^5
先把中位数mid给找出来
这里注意要根据题目的公式sorted_arr[(n-1)/2]
是中位数 偶数情况不是小数来的
那么这里可以直接对升序排序得到sorted_arr
来得到中位数
得到中位数之后 其实对于arr来说 强与弱其实是个大小关系
你只需要根据这个大小关系来进行对arr排序就行
最后取前k个即可
总的时间复杂度排序用时O(nlogn)
其实可以直接在原数组进行两次排序都没有关系的
比赛时候找中位数我另外开了个数组
class Solution {
public:
vector<int> getStrongest(vector<int>& arr, int k) {
vector<int> v=arr; //找中位数的数组
sort(v.begin(),v.end());
int n=arr.size();
int mid=v[(n-1)/2];
sort(arr.begin(),arr.end(),[mid](int a,int b)->bool{
if(abs(a-mid)==abs(b-mid)) return a>b;
return abs(a-mid)>abs(b-mid);
}); //lambda表达式 根据题目的大小关系排序
vector<int> ans;
for(int i=0;i<k;i++)ans.push_back(arr[i]); //前k个
return ans;
}
};
你有一个只有一个标签页的 浏览器 ,一开始你浏览的网页是 homepage ,你可以访问其他的网站 url ,也可以在浏览历史中后退 steps 步或前进 steps 步。
请你实现 BrowserHistory 类:
示例
输入:
[“BrowserHistory”,“visit”,“visit”,“visit”,“back”,“back”,“forward”,“visit”,“forward”,“back”,“back”]
[[“leetcode.com”],[“google.com”],[“facebook.com”],[“youtube.com”],[1],[1],[1],[“linkedin.com”],[2],[2],[7]]
输出:
[null,null,null,null,“facebook.com”,“google.com”,“facebook.com”,null,“linkedin.com”,“google.com”,“leetcode.com”]
解释:
BrowserHistory browserHistory = new BrowserHistory(“leetcode.com”);
browserHistory.visit(“google.com”); // 你原本在浏览 “leetcode.com” 。访问 “google.com”
browserHistory.visit(“facebook.com”); // 你原本在浏览 “google.com” 。访问 “facebook.com”
browserHistory.visit(“youtube.com”); // 你原本在浏览 “facebook.com” 。访问 “youtube.com”
browserHistory.back(1); // 你原本在浏览 “youtube.com” ,后退到 “facebook.com” 并返回 “facebook.com”
browserHistory.back(1); // 你原本在浏览 “facebook.com” ,后退到 “google.com” 并返回 “google.com”
browserHistory.forward(1); // 你原本在浏览 “google.com” ,前进到 “facebook.com” 并返回 “facebook.com”
browserHistory.visit(“linkedin.com”); // 你原本在浏览 “facebook.com” 。 访问 “linkedin.com”
browserHistory.forward(2); // 你原本在浏览 “linkedin.com” ,你无法前进任何步数。
browserHistory.back(2); // 你原本在浏览 “linkedin.com” ,后退两步依次先到 “facebook.com” ,然后到 “google.com” ,并返回 “google.com”
browserHistory.back(7); // 你原本在浏览 “google.com”, 你只能后退一步到 “leetcode.com” ,并返回 “leetcode.com”
提示
- 1 <= homepage.length <= 20
后退这个操作很容易就能想到栈的操作
而前进就很容易想到反向栈的操作
所以结合起来就是用的对顶栈来模拟
栈1表示当前和历史 栈2表示可以前进的
时间复杂度大概是前进后退每次都要进行O(steps)次移动元素
访问的话为O(1)
class BrowserHistory {
public:
stack<string> stk1,stk2;
BrowserHistory(string homepage) {
stk1.push(homepage); //初始
}
void visit(string url) {
stk1.push(url); //进栈
while(stk2.size())stk2.pop(); //清空前进栈 栈没有clear()
}
string back(int steps) {
while(stk1.size()>1&&steps--) //后退至多steps
{
stk2.push(stk1.top());
stk1.pop();
}
if(stk1.size())return stk1.top();
else return ""; //应该不会有这种调用情况
}
string forward(int steps) {
while(stk2.size()&&steps--) //前进至多steps
{
stk1.push(stk2.top());
stk2.pop();
}
if(stk1.size())return stk1.top();
else return ""; //应该不会有这种调用情况
}
};
在一个小城市里,有 m 个房子排成一排,你需要给每个房子涂上 n 种颜色之一(颜色编号为 1 到 n )。有的房子去年夏天已经涂过颜色了,所以这些房子不需要被重新涂色。
我们将连续相同颜色尽可能多的房子称为一个街区。(比方说 houses = [1,2,2,3,3,2,1,1] ,它包含 5 个街区 [{1}, {2,2}, {3,3}, {2}, {1,1}]。)
给你一个数组 houses ,一个 m * n 的矩阵 cost 和一个整数 target ,其中:
请你返回最小总花费,使得每个房子都被涂色后,恰好组成 target 个街区,如果没有涂色方案,请返回 -1 。
示例 1
输入:houses = [0,0,0,0,0], cost = [[1,10],[10,1],[10,1],[1,10],[5,1]], m = 5, n = 2, target = 3
输出:9
解释:房子涂色方案为 [1,2,2,1,1]
此方案包含 target = 3 个街区,分别是 [{1}, {2,2}, {1,1}]。
涂色的总花费为 (1 + 1 + 1 + 1 + 5) = 9。
示例 2
输入:houses = [0,2,1,2,0], cost = [[1,10],[10,1],[10,1],[1,10],[5,1]], m = 5, n = 2, target = 3
输出:11
解释:有的房子已经被涂色了,在此基础上涂色方案为 [2,2,1,2,2]
此方案包含 target = 3 个街区,分别是 [{2,2}, {1}, {2,2}]。
给第一个和最后一个房子涂色的花费为 (10 + 1) = 11。
示例 3
输入:houses = [0,0,0,0,0], cost = [[1,10],[10,1],[1,10],[10,1],[1,10]], m = 5, n = 2, target = 5
输出:5
示例 4
输入:houses = [3,1,2,3], cost = [[1,1,1],[1,1,1],[1,1,1],[1,1,1]], m = 4, n = 3, target = 3
输出:-1
解释:房子已经被涂色并组成了 4 个街区,分别是 [{3},{1},{2},{3}] ,无法形成 target = 3 个街区。
提示
- m == houses.length == cost.length
这种一看就是dp的最小花费问题
而且是线性dp 因为刷墙可以从左到右依次遍历观察(街区是否增加只和它的上一个有关)
首先我们来规定状态:
dp[i][j][k]
表示为
的最小花费
也就是说这些状态都是子问题的答案
先上推导出来的状态转移方程:
dp[i][j][k]=min(dp[i-1][0~n][j==jj?k:k-1])+cost[i][j]
其中jj为0~n
是什么意思呢?
首先我们要算出某个状态ijk时候最小花费
只需要看下前面的那个房子涂的所有颜色哪个最小即可
所以dp[i-1][0~n][]
应该是很容易理解的
重点在k这里 因为我们是固定街区的值的 而街区的值和上一个有关 具体表现为如何和上一个颜色一样就街区数一样 不一样就当前街区数会+1
因此就有了dp[][][j==jj?k:k-1]
如果当前房子已经涂过颜色 那么自然是不需要选择j是多少 j就是houses[i]
而且注意不需要花费
那么这个房子的作用就是起到了过滤其他状态 会把其他状态设置为非法(代码具体表现为答案值为无穷大)
初始化小细节:
初始化dp的时候应该只把dp[0][0~j][0]
设置为0
这里i从1开始 方便转移 也就是i==0
是特殊无意义状态
因为只有第一个房子允许从k==0
转移过来
总的时间复杂度是O(mn^3)
class Solution {
public:
int dp[105][25][105]; //dp状态
int minCost(vector<int>& houses, vector<vector<int>>& cost, int m, int n, int target) {
memset(dp,0x3f,sizeof(dp)); //全部初始化为非法
for(int i=0;i<n;i++)dp[0][i][0]=0; //只允许i==1从k==0转移过来
for(int i=1;i<=m;i++)
for(int j=0;j<n;j++)
for(int k=1;k<=target;k++)
{
if(houses[i-1]){ //如果已经涂色了
if(j==houses[i-1]-1) //只有j和这个颜色相同才是合法的 否则不填充这个状态
for(int jj=0;jj<n;jj++)
dp[i][j][k]=min(dp[i][j][k],dp[i-1][jj][jj==j?k:k-1]);
continue;
}
else{
for(int jj=0;jj<n;jj++) //遍历前一个的所有颜色情况
dp[i][j][k]=min(dp[i][j][k],dp[i-1][jj][jj==j?k:k-1]+cost[i-1][j]);
}
}
int ans=0x3f3f3f3f;
for(int j=0;j<n;j++)ans=min(ans,dp[m][j][target]); //找最小的答案 我们不知道最后填哪个颜色更优
return ans==0x3f3f3f3f?-1:ans;
}
};