[Leetcode Weekly Contest]272
链接:LeetCode
[Leetcode]2108. 找出数组中的第一个回文字符串
给你一个字符串数组 words ,找出并返回数组中的 第一个回文字符串 。如果不存在满足要求的字符串,返回一个 空字符串 "" 。
回文字符串 的定义为:如果一个字符串正着读和反着读一样,那么该字符串就是一个 回文字符串 。
遍历即可。
class Solution {
private boolean isPalindrome(String word) {
int start = 0, end = word.length()-1;
while(start < end) {
if(word.charAt(start++) != word.charAt(end--)) {
return false;
}
}
return true;
}
public String firstPalindrome(String[] words) {
for(var word:words) {
if(isPalindrome(word)) return word;
}
return "";
}
}
[Leetcode]2109. 向字符串添加空格
给你一个下标从 0 开始的字符串 s ,以及一个下标从 0 开始的整数数组 spaces 。
数组 spaces 描述原字符串中需要添加空格的下标。每个空格都应该插入到给定索引处的字符值 之前 。
例如,s = "EnjoyYourCoffee" 且 spaces = [5, 9] ,那么我们需要在 'Y' 和 'C' 之前添加空格,这两个字符分别位于下标 5 和下标 9 。因此,最终得到 "Enjoy Your Coffee" 。
请你添加空格,并返回修改后的字符串。
暴力循环即可。注意拼接String可以用StringBuilder。
class Solution {
public String addSpaces(String s, int[] spaces) {
int n = s.length();
int sn = spaces.length;
StringBuilder SB = new StringBuilder();
int si = 0;
int cnt = -1;
for (int i = 0; i < n; i ++)
{
cnt ++;
if (si < sn && cnt == spaces[si])
{
SB.append(' ');
si ++;
}
SB.append(s.charAt(i));
}
return SB.toString();
}
}
[Leetcode]2110. 股票平滑下跌阶段的数目
给你一个整数数组 prices ,表示一支股票的历史每日股价,其中 prices[i] 是这支股票第 i 天的价格。
一个 平滑下降的阶段 定义为:对于 连续一天或者多天 ,每日股价都比 前一日股价恰好少 1 ,这个阶段第一天的股价没有限制。
请你返回 平滑下降阶段 的数目。
动态规划,如果是平滑阶段就累加上一次的状态,否则就为1。
class Solution {
public long getSubDesent(double steps)
{
return (long)(steps / 2. * (steps-1));
}
public long getDescentPeriods(int[] prices) {
int step = 1;
long res = prices.length;
for(int ind = 1; ind < prices.length; ind ++) {
if(prices[ind] == prices[ind-1] - 1) step ++;
else {
res += getSubDesent(step);
step = 1;
}
}
if(step > 1) res += getSubDesent(step);
return res;
}
}
[Leetcode]2111. 使数组 K 递增的最少操作次数
给你一个下标从 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 递增的 最少操作次数 。
分组+二分 O(NlogN)。
两个难点,第一个是想到求最长递增子序列。对于给定的一个序列,如果我们希望通过修改最少的元素,使得它单调递增,那么最少需要修改的元素个数,就是「序列的长度」减去「序列的最长递增子序列」的长度。
第二个是怎么求序列的最长非严格递增子序列。参考最长递增子序列, 不同的是,我们在求非严格递增子序列长度的时候,假设遍历的值为target,则二分需要找到严格大于target的值。想象这样一个例子:3331112,在循环中,如果我们替换大于等于target的值最后会出现123,无法得出长度为4的结论,理由是我们在每次加入1的时候没有替换到3的位置。相通这一点,整个算法也就很好算了。
class Solution {
public int kIncreasing(int[] arr, int k) {
int res = 0;
if(k >= arr.length) return res;
List<ArrayList<Integer>> subArray = new ArrayList<>(k);
for(int ind=0;ind<arr.length;ind++){
if(ind < k) subArray.add(new ArrayList<Integer>());
int index = ind % k;
subArray.get(index).add(arr[ind]);
}
for(var list:subArray) {
res += getMinOperation(list);
}
return res;
}
private int getMinOperation(List<Integer> list) {
List<Integer> stack = new ArrayList<>();
int res = 0;
for(int i=0;i<list.size();++i) {
int target = list.get(i);
if(stack.isEmpty() || target>=stack.get(stack.size()-1)) stack.add(target);
else stack.set(getFirstLargerIndex(stack, target), target);
}
return list.size() - stack.size();
}
private int getFirstLargerIndex(List<Integer> nums, int target) {
int lo = 0, hi = nums.size()-1;
while(lo <= hi) {
int mid = lo+(hi-lo)/2;
if(nums.get(mid) <= target) lo = mid + 1;
else hi = mid - 1;
}
return lo;
}
}