目录
今天还是继续刷剑指~
1. 扑克牌顺子
难度简单229
从若干副扑克牌中随机抽 5
张牌,判断是不是一个顺子,即这5张牌是不是连续的。2~10为数字本身,A为1,J为11,Q为12,K为13,而大、小王为 0 ,可以看成任意数字。A 不能视为 14。
示例 1:
输入: [1,2,3,4,5] 输出: True
示例 2:
输入: [0,0,1,2,5] 输出: True
限制:
数组长度为 5
数组的数取值为 [0, 13] .
写着写着思路就清晰的模拟题。
可以判定不是顺子:除王外有重复元素,最大值和最小值相差超过4
可以判定是顺子:有4/5个王,除了不是顺子的情况
class Solution {
public:
bool isStraight(vector<int>& nums) {
int count = 0;
int minVal = INT_MAX;
int maxVal = INT_MIN;
unordered_set<int> set;
for(int i = 0; i < nums.size(); i++){
if(nums[i] == 0){
count++;
}
else{
if(set.count(nums[i])){
return false;//不能有非0元素重复
}
set.insert(nums[i]);
minVal = min(minVal,nums[i]);
maxVal = max(maxVal,nums[i]);
}
if(count == 4){//四个大王已经可以保证是顺子
return true;
}
}
if(maxVal - minVal > 4){//最大值和最小值相差不能超过4否则无法构成顺子
return false;
}
return true;
}
};
2. 圆圈剩下的数字
难度简单597
0,1,···,n-1这n个数字排成一个圆圈,从数字0开始,每次从这个圆圈里删除第m个数字(删除后从下一个数字开始计数)。求出这个圆圈里剩下的最后一个数字。
例如,0、1、2、3、4这5个数字组成一个圆圈,从数字0开始每次删除第3个数字,则删除的前4个数字依次是2、0、4、1,因此最后剩下的数字是3。
示例 1:
输入: n = 5, m = 3 输出: 3
示例 2:
输入: n = 10, m = 17 输出: 2
限制:
1 <= n <= 10^5
1 <= m <= 10^6
约瑟夫环问题。挣扎着试图模拟,失败,看了题解才发现可以递归。
长度为n的序列,先删除第m%n个元素,剩下的是一个长度为n-1的序列,问题就转化为在长度n-1的序列中最后剩下的数字。
然而怎么从n-1剩下的数字下标转化到n剩下的数字下标,我看了一会推导才明白...
设f(n,m)=y,表示在长度为n的序列中,每次删除第m个数字(下标为(m-1)%n),最后剩下的数字的下标为y。
设f(n-1,m)=x,表示在长度为n-1的序列中,每次删除第m个数字,最后剩下的数字的下标为x。
在长度为n的序列中删除后,往后数x+1个,就到达长度为n-1的序列中剩下的数字,这个数字在原序列中的下标为((m-1)%n+(x+1))%n=(m+x)%n.
class Solution {
int f(int n, int m) {
if (n == 1) {
return 0;
}
int x = f(n - 1, m);
return (m + x) % n;
}
public:
int lastRemaining(int n, int m) {
return f(n, m);
}
};
3. 股票的最大利润
假设把某股票的价格按照时间先后顺序存储在数组中,请问买卖该股票一次可能获得的最大利润是多少?
示例 1:
输入: [7,1,5,3,6,4] 输出: 5 解释: 在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。 注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格。
示例 2:
输入: [7,6,4,3,1] 输出: 0 解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。
限制:
0 <= 数组长度 <= 10^5
这道题之前跟着代码随想录做过,再复习一下动态规划的基本步骤:
1.确定dp数组和下标的含义:dp[i]表示到第i天能获得的最大利润
2.确定递推公式:截至第i天能获得的最大利润=截至前一天能获得的最大利润和第i天的利润取最大值
3.初始化dp数组:第一天利润为0
4.确定遍历顺序:因为第i天的利润要从第i-1天推出,从前往后
5.举例推导dp数组
class Solution {
public:
int maxProfit(vector<int>& prices) {
if(prices.empty()){
return 0;
}
vector<int> dp(prices.size());//1.dp[i]到第i天能获得的最大利润
int minPrice = prices[0];//到当前位置的最小价格
dp[0] = 0;
for(int i = 1;i < prices.size(); i++){
minPrice = min(minPrice,prices[i]);//更新到当天为止的最小价格
dp[i] = max(dp[i - 1],prices[i] - minPrice);//2.第i天的最大利润=max(到前一天的最大利润,今天卖出的利润)
}
return dp.back();
}
};
4. 不用+做加法
写一个函数,求两个整数之和,要求在函数体内不得使用 “+”、“-”、“*”、“/” 四则运算符号。
示例:
输入: a = 1, b = 1 输出: 2
提示:
a
,b
均可能是负数或 0- 结果不会溢出 32 位整数
前几天刚接触过位运算,记住了两个比较常用的结论:
a&b:a+b的进位
a^b:a+b(无进位)
每一位的结果包括本位和、进位两个部分,本位和就是上面的无进位和,用异或实现,进位是低位向当前位的进位,用与实现。
class Solution {
public:
int add(int a, int b) {
while(b){//直到不再向前产生进位
int sum = a ^ b;//本位和+上一位产生的进位
b = (unsigned int)(a & b) << 1;//a+b在当前位产生的进位//*负数移位需要转换成unsigned int
a = sum;
}
return a;
}
};