2108. 找出数组中的第一个回文字符串
导航
- [2108. 找出数组中的第一个回文字符串](https://leetcode-cn.com/problems/find-first-palindromic-string-in-the-array/)
- [2109. 向字符串添加空格](https://leetcode-cn.com/problems/adding-spaces-to-a-string/)
- [2110. 股票平滑下跌阶段的数目](https://leetcode-cn.com/problems/number-of-smooth-descent-periods-of-a-stock/)
- [2111. 使数组 K 递增的最少操作次数](https://leetcode-cn.com/problems/minimum-operations-to-make-the-array-k-increasing/)
1.题意:
给你一个字符串数组 words ,找出并返回数组中的 第一个回文字符串 。如果不存在满足要求的字符串,返回一个 空字符串 “” 。
回文字符串 的定义为:如果一个字符串正着读和反着读一样,那么该字符串就是一个 回文字符串 。
示例 1:
输入:words = ["abc","car","ada","racecar","cool"]
输出:"ada"
解释:第一个回文字符串是 "ada" 。
注意,"racecar" 也是回文字符串,但它不是第一个。
示例 2:
输入:words = ["notapalindrome","racecar"]
输出:"racecar"
解释:第一个也是唯一一个回文字符串是 "racecar" 。
示例 3:
输入:words = ["def","ghi"]
输出:""
解释:不存在回文字符串,所以返回一个空字符串。
2.解题思路:
- 给定数据为:
1 <= words.length <= 100
1 <= words[i].length <= 100
- 暴力即可
3.代码:
class Solution {
public:
bool isPalind(string str)
{
int i = 0;
int j = str.size() - 1;
while (i < j)
{
if (str[i] != str[j])
return false;
++i;
--j;
}
return true;
}
string firstPalindrome(vector<string>& words)
{
for (const auto &it : words)
{
if (isPalind(it))
return it;
}
return "";
}
};
2109. 向字符串添加空格
1.题意:
给你一个下标从 0 开始的字符串 s ,以及一个下标从 0 开始的整数数组 spaces 。
数组 spaces 描述原字符串中需要添加空格的下标。每个空格都应该插入到给定索引处的字符值 之前 。
例如,s = “EnjoyYourCoffee” 且 spaces = [5, 9] ,那么我们需要在 ‘Y’ 和 ‘C’ 之前添加空格,这两个字符分别位于下标 5 和下标 9 。因此,最终得到 “Enjoy Your Coffee” 。
请你添加空格,并返回修改后的字符串。
示例 1:
输入:s = "LeetcodeHelpsMeLearn", spaces = [8,13,15]
输出:"Leetcode Helps Me Learn"
解释:
下标 8、13 和 15 对应 "LeetcodeHelpsMeLearn" 中加粗斜体字符。
接着在这些字符前添加空格。
示例 2:
输入:s = "icodeinpython", spaces = [1,5,7,9]
输出:"i code in py thon"
解释:
下标 1、5、7 和 9 对应 "icodeinpython" 中加粗斜体字符。
接着在这些字符前添加空格。
示例 3:
输入:s = "spacing", spaces = [0,1,2,3,4,5,6]
输出:" s p a c i n g"
解释:
字符串的第一个字符前可以添加空格。
2.题解思路:
- 先创建一个目标字符串,长度就是原字符长度 + 空格长度
- 然后双指针遍历两个字符串
- 如果是spaces的值,那么目标字符串下标就替换为空格
- 如果不是就替换为源字符串的值
- 直到全部遍历完毕即可
3.代码:
class Solution {
public:
string addSpaces(string s, vector<int>& spaces)
{
int n = s.size();
int length = n + spaces.size();
string res(length,' ');
int j = length - 1;
int i = n - 1;
int k = spaces.size() - 1;
while (i >= 0 && j >= i)
{
if (k >= 0 && i == spaces[k] - 1) //因为我创建的时候就初始化为空格,所以直接跳过即可
{
--j;
--k;
continue;
}
else
{
res[j] = s[i];
--j;
--i;
}
}
return res;
}
};
2110. 股票平滑下跌阶段的数目
1.题意:
给你一个整数数组 prices ,表示一支股票的历史每日股价,其中 prices[i] 是这支股票第 i 天的价格。
一个 平滑下降的阶段 定义为:对于 连续一天或者多天 ,每日股价都比 前一日股价恰好少 1 ,这个阶段第一天的股价没有限制。
请你返回 平滑下降阶段 的数目。
示例 1:
输入:prices = [3,2,1,4]
输出:7
解释:总共有 7 个平滑下降阶段:
[3], [2], [1], [4], [3,2], [2,1] 和 [3,2,1]
注意,仅一天按照定义也是平滑下降阶段。
示例 2:
输入:prices = [8,6,7,7]
输出:4
解释:总共有 4 个连续平滑下降阶段:[8], [6], [7] 和 [7]
由于 8 - 6 ≠ 1 ,所以 [8,6] 不是平滑下降阶段。
示例 3:
输入:prices = [1]
输出:1
解释:总共有 1 个平滑下降阶段:[1]
2.解题思路:
- 经典dp题
- 当前值如果小于前一个值,那么能组成的天数就是前一个值的天数,再加上自己.
- 初始化当前天均为1,它自己能组成一天.
- 所以转化方程为:
dp[i] += dp[i - 1]
.只在前一天比当前天大1的情况下可以转化.
- 用一个变量存储,记得用long long,否则会溢出
3.代码
class Solution {
public:
long long getDescentPeriods(vector<int>& prices)
{
int n = prices.size();
if (n == 0)
return 0;
vector<long long> dp(n,1);
long long res = 1;
for (int i = 1; i < prices.size(); ++i)
{
if (prices[i - 1] - prices[i] == 1)
{
dp[i] += dp[i - 1];
}
res += dp[i];
}
return res;
}
};
2111. 使数组 K 递增的最少操作次数
1.题意:
给你一个下标从 0 开始包含 n 个正整数的数组 arr ,和一个正整数 k 。
如果对于每个满足 k <= i <= n-1 的下标 i ,都有 arr[i-k] <= arr[i] ,那么我们称 arr 是 K 递增 的。
比方说,
arr = [4, 1, 5, 2, 6, 2]
对于 k = 2 是 K 递增的,因为:
arr[0] <= arr[2] (4 <= 5)
arr[1] <= arr[3] (1 <= 2)
arr[2] <= arr[4] (5 <= 6)
arr[3] <= arr[5] (2 <= 2)
但是,相同的数组 arr 对于 k = 1 不是 K 递增的(因为 arr[0] > arr[1]),对于 k = 3 也不是 K 递增的(因为 arr[0] > arr[3] )。
每一次 操作 中,你可以选择一个下标
i
并将arr[i]
改成任意 正整数。请你返回对于给定的
k
,使数组变成 K 递增的 最少操作次数 。
示例 1:
输入:arr = [5,4,3,2,1], k = 1
输出:4
解释:
对于 k = 1 ,数组最终必须变成非递减的。
可行的 K 递增结果数组为 [5,6,7,8,9],[1,1,1,1,1],[2,2,3,4,4] 。它们都需要 4 次操作。
次优解是将数组变成比方说 [6,7,8,9,10] ,因为需要 5 次操作。
显然我们无法使用少于 4 次操作将数组变成 K 递增的。
示例 2:
输入:arr = [4,1,5,2,6,2], k = 2
输出:0
解释:
这是题目描述中的例子。
对于每个满足 2 <= i <= 5 的下标 i ,有 arr[i-2] <= arr[i] 。
由于给定数组已经是 K 递增的,我们不需要进行任何操作。
示例 3:
输入:arr =[12,6,12,6,14,2,13,17,3,8,11,7,4,11,18,8,8,3], k = 1
输出:12
2.解题思路
- 找出每个子数组的最长上升子序列
- 然后加上长度 - 最长上升子序列即可
- 问题转化为求多个数组的最长子序列问题
- 动态规划,O(n²)会超时
- 只能用贪心 + 二分, O(nlogn);
3.代码
class Solution {
public:
int addNum(vector<int> &nums) //直接用dp求,超时
{
int n = nums.size();
vector<int> dp(n, 1);
int res = 1;
for (int i = 1; i < n; ++i)
{
for (int j = 0; j < i; ++j)
{
if (nums[i] >= nums[j])
dp[i] = max(dp[i], dp[j] + 1);
}
res = max(res, dp[i]);
}
return n - res;
}
int kIncreasing(vector<int>& arr, int k)
{
int n = arr.size();
int res = 0;
for (int i = 0; i < k; ++i)
{
vector<int> temp;
for (int j = i; j < n; j += k)
{
temp.push_back(arr[j]);
}
res += addNum(temp);
}
return res;
}
};
//优化版本
class Solution {
public:
int addNum(vector<int> &nums) //利用贪心和二分,降低时间复杂度
{
int n = nums.size();
vector<int> LIT; //维护一个最长上升子序列的数组,改数组为递增
for(const auto num : nums)
{
auto it = upper_bound(LIT.begin(),LIT.end(),num); //每次都在递增的数组中,找到第一个比当前值小的元素.因
if(it == LIT.end())
LIT.push_back(num); //如果没有,说明他就是最大的,加到后面
else
*it = num; //找到了就替换,小的价值更大.虽然出来的子序列不一定是对的,但是长度一定是对的
}
return n - LIT.size(); //返回修改的次数
}
int kIncreasing(vector<int>& arr, int k)
{
int n = arr.size();
int res = 0;
for (int i = 0; i < k; ++i)
{
vector<int> temp; //变成多个子数组
for (int j = i; j < n; j += k)
{
temp.push_back(arr[j]);
}
res += addNum(temp);
}
return res;
}
};