i = 0
while(i
这题我比赛时用的并查集。看灵神视频学了个分组循环的做法。
对于每个分组,如果可以交换,则扩展分组的窗口,直至达到尽头或者不能交换为止。这样这个分组里的数都是可以任意交换的,因此就可以对这个分组进行排序。对每个分组排序后如果能使得整个数组有序,那么就成功。
import java.util.Arrays;
class Solution {
public boolean canSortArray(int[] nums) {
int i = 0;
int start;
int n = nums.length;
while(inums[i]){
return false;
}
}
return true;
}
}
入门题。分组记录每个连续字符子串长度,维护最大值。
class Solution {
public int maxPower(String s) {
char[] ch = s.toCharArray();
int i = 0;
int n = ch.length;
int max = 0;
while(i
入门题。分组记录0/1子串长度,维护最大值,最后比较。
class Solution {
public boolean checkZeroOnes(String s) {
int max0 = 0;
int max1 = 1;
char[] ch = s.toCharArray();
int i = 0;
int n = ch.length;
while(i< n){
int start = i;
char c = ch[i];
boolean which = c =='1';
while(imax0;
}
}
入门题。分组检查连续相同子串长度,超过2就缩减到2,拼到答案里即可。
class Solution {
public String makeFancyString(String s) {
char[] ch = s.toCharArray();
StringBuilder sb = new StringBuilder();
int i = 0;
int n = ch.length;
while(i
入门题。分组查询每段平滑下跌阶段。贡献是(l+1)*l/2(等差数列),累加即可。
class Solution {
public long getDescentPeriods(int[] prices) {
int i = 0;
int start;
int n = prices.length;
long ans = 0;
while(i
每日一题+入门题。分组查询交替子数组长度,维护最大值
class Solution {
public int alternatingSubarray(int[] nums) {
int n = nums.length;
int max = -1;
int i = 0;
int start;
while(istart){
max = Math.max(max,i-start+1);
}
if(!(i>start)){
i++;
}
}
return max;
}
}
入门题。分组查询递增1的区间,记录下来整合成目标格式的字符串即可。
import java.util.ArrayList;
import java.util.List;
class Solution {
public List summaryRanges(int[] nums) {
ArrayList> l = new ArrayList<>();
int i = 0;
int n = nums.length;
while(i tmp = new ArrayList<>();
while(i print(List> l){
ArrayList ans = new ArrayList<>();
for (List is : l) {
StringBuilder sb = new StringBuilder();
if(is.size()==1){
sb.append(is.get(0));
}else{
sb.append(is.get(0)).append("->").append(is.get(is.size()-1));
}
ans.add(sb.toString());
}
return ans;
}
}
入门题。分组查询满足条件的区间,维护最大值即可。
class Solution {
public int longestAlternatingSubarray(int[] nums, int threshold) {
int max = 0;
int i = 0;
int start;
int n = nums.length;
while(ithreshold){
i++;
continue;
}
start = i;
while(i
这道题我没想出来分组循环的写法。就想了个最好情况下O(nlgn)的散列表写法。思路大致就是,每个数最终都要等于那个最小数。每一批相同的数都要往下逐级递减。举个例子:
[ 1 1 2 2 3 3 ]
两个3要都减少到2,然后4个2减少到1。维护一个有序列表模拟这个过程即可。
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
class Solution {
public int reductionOperations(int[] nums) {
int ops = 0;
// 最终都会减小到最小值
TreeMap tm = new TreeMap<>();
for (int num : nums) {
mAdd(tm,num);
}
// 累加即可
int prefix = 0;
Integer[] arr = tm.keySet().toArray(Integer[]::new);
for(int i=arr.length-1;i>=0;i--){
prefix += tm.get(arr[i]);
ops+=prefix;
}
ops-=prefix;
return ops;
}
private void mAdd(Map m,int num){
m.put(
num,m.getOrDefault(num,0)+1
);
}
}
后来我发现自己sb了,这个写法完全可以改成严格的O(nlgn)的,因为减少操作的时候,跟元素的索引根本没关系。
prefix相当于每个分组到最小元素的步长。每遍历到某个分组的元素,就加上一次这个步长。如果是下一个分组就给步长+1。
import java.util.Arrays;
class Solution {
public int reductionOperations(int[] nums) {
int ops = 0;
Arrays.sort(nums);
int prefix = 0; // 相当于步长
for(int i=1;i
少见的博弈类型的题。这道题比较简单,只要统计双方的可以操作的次数就可以了。可能会疑惑,有没有可能A操作完给了B新的操作机会?或者反过来,B给A机会?这是不可能的,因为要求连续子数组的数量大于等于3,所以删到长度≤2的时候就不能删了,就不可能给对方新的机会,这个≤2的子串会一直卡着对面操作。
统计操作次数很简单。分组统计连续子数组长度,为自己的操作次数贡献Math.max(0,l-2)次机会。
class Solution {
public boolean winnerOfGame(String colors) {
// 统计分别可以删几次就行
int opA = 0;
int opB = 0;
char[] ch = colors.toCharArray();
int n = ch.length;
int i = 0;
int start;
while(i0 && opA>opB;
}
}
入门题。查询连续相同子串的长度,计算贡献。1+2+…+l即可。
取模想不清楚?那就直接在能取模的地方全部取模,我愿称之为取模仙人。
class Solution {
int mod = (int)1e9+7;
public int countHomogenous(String s) {
char[] ch = s.toCharArray();
long ans = 0;
int i=0;
int start;
int n = ch.length;
while(i
入门题。查询连续相同的子串,记录需要最长时间删除的代价,当前分组总体时间减去该最长时间即为分组的最短时间,每个分组的最短时间加起来就是总体的最短时间。
class Solution {
public int minCost(String colors, int[] neededTime) {
char[] ch = colors.toCharArray();
int n = ch.length;
int i = 0;
int start;
int ans = 0;
while(i
入门题。对于每个分组记录长度,维护当前最大的字符,要求后续的全部大于这个字符。同时记录所有出现过的字符,如果到最后5个元音字符全部出现过,那么维护最大值。
import java.util.Arrays;
import java.util.HashSet;
class Solution {
static char[] vowels = new char[]{'a','e','i','o','u'};
public int longestBeautifulSubstring(String word) {
char[] ch = word.toCharArray();
int n = ch.length;
int i = 0;
int max = 0;
while(i vs = new HashSet<>();
int start = i;
char last = ch[i];
while(i=last){
last = ch[i];
vs.add(ch[i]);
i++;
}
if(check(vs)){
max = Math.max(max,i-start);
}
}
return max;
}
private boolean check(HashSet vs){
return vs.size()==5;
}
}