定义
贪心算法(又称贪婪算法)是指,在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,算法得到的是在某种意义上的局部最优解。贪心算法不是对所有问题都能得到整体最优解,关键是贪心策略的选择。也就是说,不从整体最优上加以考虑,做出的只是在某种意义上的局部最优解。选择的贪心策略必须具备无后效性,即某个状态以前的过程不会影响以后的状态,只与当前状态有关,这点和动态规划一样。贪心策略和动态规划类似,多数情况都是用来处理极值问题。
贪心算法常见问题
跳跃游戏
给定一个非负整数数组,你最初位于数组的第一个位置。数组中的每个元素代表你在该位置可以跳跃的最大长度。判断你是否能够到达最后一个位置。
输入: [2,3,1,1,4]
输出: true
解释: 我们可以先跳 1 步,从位置 0 到达 位置 1, 然后再从位置 1 跳 3 步到达最后一个位置。
来源:leetcode-cn.com/problems/ju…
var canJump = function(nums) {
let max = 0; // 能够走到的数组下标
for (let i = 0; i < nums.length; i++) {
if (max < i) return false; // 当前这一步都走不到,后面更走不到了
max = Math.max(nums[i] + i, max);
}
return true;
};
跳跃游戏 II
给定一个非负整数数组,你最初位于数组的第一个位置。 数组中的每个元素代表你在该位置可以跳跃的最大长度。 你的目标是使用最少的跳跃次数到达数组的最后一个位置。
输入: [2,3,1,1,4]
输出: 2
解释: 跳到最后一个位置的最小跳跃数是 2。
从下标为 0 跳到下标为 1 的位置,跳 1 步,然后跳 3 步到达数组的最后一个位置。
来源:leetcode-cn.com/problems/ju…
var jump = function(nums) {
let n = nums.length, count = 0, father = 0, end = 0;
for (let i = 0; i < n - 1; i++) {
father = Math.max(father, nums[i] + i)
if(i === end) {
count += 1;
end = father;
}
}
return count;
};
分发饼干
假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。 对每个孩子 i,都有一个胃口值 g[i],这是能让孩子们满足胃口的饼干的最小尺寸;并且每块饼干 j,都有一个尺寸 s[j] 。如果 s[j] >= g[i],我们可以将这个饼干 j 分配给孩子 i ,这个孩子会得到满足。你的目标是尽可能满足越多数量的孩子,并输出这个最大数值。
输入: g = [1,2,3], s = [1,1]
输出: 1
解释:
你有三个孩子和两块小饼干,3个孩子的胃口值分别是:1,2,3。
虽然你有两块小饼干,由于他们的尺寸都是1,你只能让胃口值是1的孩子满足。
所以你应该输出1。
来源:leetcode-cn.com/problems/as…
var findContentChildren = function(g, s) {
g.sort((a, b) => a - b);
s.sort((a, b) => a - b);
let count = 0, idx = 0;
for (let i = 0; i < s.length; i++) {
if(s[i] >= g[idx]) {
count++;
idx++;
if(idx >= g.length) {
break;
}
}
}
return count;
};
优势洗牌
给定两个大小相等的数组 A 和 B,A 相对于 B 的优势可以用满足 A[i] > B[i] 的索引 i 的数目来描述。 返回 A 的任意排列,使其相对于 B 的优势最大化。
输入:A = [2,7,11,15], B = [1,10,4,11]
输出:[2,11,7,15]
来源:leetcode-cn.com/problems/ad…
var advantageCount = function(A, B) {
//排序
A.sort((a,b)=>a-b);
const getMinLargeNum = function(num){
for(let i=0;i<A.length;i++){
//找到第一个比num大的数,返回
if(num<A[i]){
return i;
}
}
//找不到,取第一个,因为第一个是最小的,是下等马
return 0;
}
let ans = [];
for(let i=0;i<B.length;i++){
let idx = getMinLargeNum(B[i]);
ans.push(A[idx]);
A.splice(idx,1);
}
return ans;
};
摆动序列
如果连续数字之间的差严格地在正数和负数之间交替,则数字序列称为**摆动序列。**第一个差(如果存在的话)可能是正数或负数。少于两个元素的序列也是摆动序列。
例如, [1,7,4,9,2,5] 是一个摆动序列,因为差值 (6,-3,5,-7,3) 是正负交替出现的。相反, [1,4,7,2,5] 和 [1,7,4,5,5] 不是摆动序列,第一个序列是因为它的前两个差值都是正数,第二个序列是因为它的最后一个差值为零。
给定一个整数序列,返回作为摆动序列的最长子序列的长度。 通过从原始序列中删除一些(也可以不删除)元素来获得子序列,剩下的元素保持其原始顺序。
输入: [1,17,5,10,13,15,10,5,16,8]
输出: 7
解释: 这个序列包含几个长度为 7 摆动序列,其中一个可为[1,17,10,13,10,16,8]。
来源:leetcode-cn.com/problems/wi…
var wiggleMaxLength = function(nums) { if(nums.length < 2) return nums.length; let down = 1, up = 1; for (let i = 1; i < nums.length; i++) { if(nums[i] > nums[i - 1]) { up = down + 1; } else if(nums[i] < nums[i - 1]) { down = up + 1; } } return Math.max(down, up);};
不含 AAA 或 BBB 的字符串
给定两个整数 A 和 B,返回任意字符串 S,要求满足:
-
S 的长度为 A + B,且正好包含 A 个 'a' 字母与 B 个 'b' 字母;
-
子串 'aaa' 没有出现在 S 中;
-
子串 'bbb' 没有出现在 S 中。
输入:A = 1, B = 2 输出:"abb" 解释:"abb", "bab" 和 "bba" 都是正确答案。
来源:leetcode-cn.com/problems/st…
var strWithout3a3b = function(A, B) {
let ans = "";
let a = 0, b = 0;
while(A > 0 || B > 0) {
while(A > 0 && ((A >= B && a < 2) || b == 2)) {
ans += 'a';
A--;
a++;
b = 0;
}
while(B > 0 && ((B >= A && b < 2) || a == 2)) {
ans += 'b';
B--;
b++;
a = 0;
}
}
return ans;
};
分割数组为连续子序列
给你一个按升序排序的整数数组 num(可能包含重复数字),请你将它们分割成一个或多个子序列,其中每个子序列都由连续整数组成且长度至少为 3 。 如果可以完成上述分割,则返回 true ;否则,返回 false 。
输入: [1,2,3,3,4,5]
输出: True
解释:
你可以分割出这样两个连续子序列 :
1, 2, 3
3, 4, 5
来源:leetcode-cn.com/problems/sp…
var isPossible = function(nums) {
const counter = {}
for(let i of nums){
counter[i] ? counter[i]++: counter[i] = 1
}
const tails = {}
for(let item of nums) {
if(tails[item]) {
tails[item]--;
tails[item +1 ] ? tails[item + 1]++ : tails[item +1 ]=1
} else if(counter[item + 1] && counter[item + 2]) {
counter[item + 1]--;
counter[item + 2]--;
tails[item + 1] ? tails[item + 1]++: tails[item + 1]=1
} else {
return false
}
counter[item]--;
}
return true;
};
划分字母区间
字符串 S 由小写字母组成。我们要把这个字符串划分为尽可能多的片段,同一字母最多出现在一个片段中。返回一个表示每个字符串片段的长度的列表。
输入:S = "ababcbacadefegdehijhklij"
输出:[9,7,8]
解释:
划分结果为 "ababcbaca", "defegde", "hijhklij"。
每个字母最多出现在一个片段中。
像 "ababcbacadefegde", "hijhklij" 的划分是错误的,因为划分的片段数较少。
来源:leetcode-cn.com/problems/pa…
var partitionLabels = function(S) {
let res = [];
let map = new Map(), start = 0, end = 0;
for (let i = 0; i < S.length; i++) {
map[S[i]] = i;
}
for (let j = 0; j < S.length; j++) {
end = Math.max(end, map[S[j]]);
if(j === end) {
res.push(end - start + 1);
start = j + 1;
}
}
return res;
};
非递增顺序的最小子序列
给你一个数组 nums,请你从中抽取一个子序列,满足该子序列的元素之和 严格 大于未包含在该子序列中的各元素之和。
如果存在多个解决方案,只需返回 长度最小 的子序列。如果仍然有多个解决方案,则返回 元素之和最大 的子序列。
与子数组不同的地方在于,「数组的子序列」不强调元素在原数组中的连续性,也就是说,它可以通过从数组中分离一些(也可能不分离)元素得到。
注意,题目数据保证满足所有约束条件的解决方案是 唯一 的。同时,返回的答案应当按 非递增顺序 排列。
输入:nums = [4,3,10,9,8]
输出:[10,9]
解释:子序列 [10,9] 和 [10,8] 是最小的、满足元素之和大于其他各元素之和的子序列。但是 [10,9] 的元素之和最大。
来源:leetcode-cn.com/problems/mi…
var minSubsequence = function(nums) {
let arr = new Array(101).fill(0);
let i, sum = 0, s = 0;
for (let i = 0; i < nums.length; ++i) {
sum += nums[i];
arr[nums[i]]++;
}
let ans = [];
for (i = 100; i >= 0; --i) {
while(arr[i]--) {
if(s + i > sum - i) {
ans.push(i)
return ans;
} else {
s += i;
sum -= i;
ans.push(i)
}
}
}
return ans;
};
玩筹码
数轴上放置了一些筹码,每个筹码的位置存在数组 chips 当中
你可以对 任何筹码 执行下面两种操作之一(不限操作次数,0 次也可以):
将第 i 个筹码向左或者右移动 2 个单位,代价为 0。
将第 i 个筹码向左或者右移动 1 个单位,代价为 1。
最开始的时候,同一位置上也可能放着两个或者更多的筹码。返回将所有筹码移动到同一位置(任意位置)上所需要的最小代价。
输入:chips = [1,2,3]
输出:1
解释:第二个筹码移动到位置三的代价是 1,第一个筹码移动到位置三的代价是 0,总代价为 1。
来源:leetcode-cn.com/problems/mi…
var minCostToMoveChips = function(chips) {
let odd = 0, even = 0;
for (let i = 0; i < chips.length; i++) {
if(chips[i] % 2 == 0) {
even++
} else {
odd++
}
}
return Math.min(even, odd)
};
K 次取反后最大化的数组和
给定一个整数数组 A,我们只能用以下方法修改该数组:我们选择某个索引 i 并将 A[i] 替换为 -A[i],然后总共重复这个过程 K 次。(我们可以多次选择同一个索引 i。) 以这种方式修改数组后,返回数组可能的最大和。
输入:A = [3,-1,0,2], K = 3
输出:6
解释:选择索引 (1, 2, 2) ,然后 A 变为 [3,1,0,2]。
来源:leetcode-cn.com/problems/ma…
var largestSumAfterKNegations = function(A, K) {
A.sort((a, b) => a - b);
for (let i = 0; i < K; i++) {
A[0] = -A[0];
A.sort((a, b) => a - b);
}
let sum = A.reduce((prev, cur) => {
return prev + cur
})
return sum;
};
柠檬水找零
在柠檬水摊上,每一杯柠檬水的售价为 5 美元。 顾客排队购买你的产品,(按账单 bills 支付的顺序)一次购买一杯。 每位顾客只买一杯柠檬水,然后向你付 5 美元、10 美元或 20 美元。你必须给每个顾客正确找零,也就是说净交易是每位顾客向你支付 5 美元。 注意,一开始你手头没有任何零钱。 如果你能给每位顾客正确找零,返回 true ,否则返回 false 。
输入:[5,5,5,10,20]
输出:true
解释:
前 3 位顾客那里,我们按顺序收取 3 张 5 美元的钞票。
第 4 位顾客那里,我们收取一张 10 美元的钞票,并返还 5 美元。
第 5 位顾客那里,我们找还一张 10 美元的钞票和一张 5 美元的钞票。
由于所有客户都得到了正确的找零,所以我们输出 true。
来源:leetcode-cn.com/problems/le…
var lemonadeChange = function(bills) {
var five = 0, ten = 0, len = bills.length;
for(let i = 0; i < bills.length; i++) {
if(bills[i] == 5) {
five++
} else if(bills[i] == 10) {
if(five == 0) {
return false;
}
five--;
ten++;
} else if(bills[i] == 20) {
if(ten > 0 && five > 0) {
ten--;
five--
} else if(five >= 3) {
five -= 3;
} else {
return false;
}
}
}
return true;
};
最后一块石头的重量
有一堆石头,每块石头的重量都是正整数。
每一回合,从中选出两块 最重的 石头,然后将它们一起粉碎。假设石头的重量分别为 x 和 y,且 x <= y。那么粉碎的可能结果如下:
- 如果
x == y,那么两块石头都会被完全粉碎; - 如果
x != y,那么重量为x的石头将会完全粉碎,而重量为y的石头新重量为y-x。
最后,最多只会剩下一块石头。返回此石头的重量。如果没有石头剩下,就返回 0。
输入:[2,7,4,1,8,1]
输出:1
解释:
先选出 7 和 8,得到 1,所以数组转换为 [2,4,1,1,1],
再选出 2 和 4,得到 2,所以数组转换为 [2,1,1,1],
接着是 2 和 1,得到 1,所以数组转换为 [1,1,1],
最后选出 1 和 1,得到 0,最终数组转换为 [1],这就是最后剩下那块石头的重量。
来源:leetcode-cn.com/problems/la…
var lastStoneWeight = function(stones) {
let len = stones.length;
while(len > 1) {
stones.sort((a, b) => a - b);
let x = stones[len - 2], y = stones[len - 1];
if(x != y) {
stones.pop();
len = stones.length;
stones[len - 1] = y - x;
} else {
stones.pop();
stones.pop();
len = stones.length;
}
}
return len < 1 ? 0 : stones[0]
};
加油站
在一条环路上有 N 个加油站,其中第 i 个加油站有汽油 gas[i] 升。 你有一辆油箱容量无限的的汽车,从第 i 个加油站开往第 i+1 个加油站需要消耗汽油 cost[i] 升。你从其中的一个加油站出发,开始时油箱为空。 如果你可以绕环路行驶一周,则返回出发时加油站的编号,否则返回 -1。 说明: 如果题目有解,该答案即为唯一答案。输入数组均为非空数组,且长度相同。输入数组中的元素均为非负数。
输入:
gas = [1,2,3,4,5]
cost = [3,4,5,1,2]
输出: 3
解释:
从 3 号加油站(索引为 3 处)出发,可获得 4 升汽油。此时油箱有 = 0 + 4 = 4 升汽油
开往 4 号加油站,此时油箱有 4 - 1 + 5 = 8 升汽油
开往 0 号加油站,此时油箱有 8 - 2 + 1 = 7 升汽油
开往 1 号加油站,此时油箱有 7 - 3 + 2 = 6 升汽油
开往 2 号加油站,此时油箱有 6 - 4 + 3 = 5 升汽油
开往 3 号加油站,你需要消耗 5 升汽油,正好足够你返回到 3 号加油站。
因此,3 可为起始索引。
来源:leetcode-cn.com/problems/ga…
var canCompleteCircuit = function(gas, cost) {
let n = gas.length;
let total_tank = 0;
let cur_tank = 0;
let starting_station = 0;
for (let i = 0; i < n; i++) {
total_tank += gas[i] - cost[i];
cur_tank += gas[i] - cost[i];
if(cur_tank < 0) {
starting_station = i + 1;
cur_tank = 0
}
}
return total_tank >= 0 ? starting_station : -1;
};
分发糖果
老师想给孩子们分发糖果,有N个孩子站成了一条直线,老师会根据每个孩子的表现,预先给他们评分。
你需要按照以下要求,帮助老师给这些孩子分发糖果:
- 每个孩子至少分配到 1 个糖果。
- 相邻的孩子中,评分高的孩子必须获得更多的糖果。
那么这样下来,老师至少需要准备多少颗糖果呢?
输入: [1,0,2]
输出: 5
解释: 你可以分别给这三个孩子分发 2、1、2 颗糖果。
来源:leetcode-cn.com/problems/ca…
var candy = function(ratings) {
var left = new Array(ratings.length).fill(1);
var right = new Array(ratings.length).fill(1);
for (var i = 1; i < ratings.length; i++) {
if(ratings[i] > ratings[i-1])
left[i] = left[i-1] + 1;
}
let count = left[ratings.length - 1];
for (let j = ratings.length - 2; j >= 0; j-- ) {
if(ratings[j] > ratings[j+1]) {
right[j] = right[j+1] + 1;
}
count += Math.max(left[j], right[j])
}
return count;
};
灌溉花园的最少水龙头数目
在 x 轴上有一个一维的花园。花园长度为 n,从点 0 开始,到点 n 结束。 花园里总共有 n + 1 个水龙头,分别位于 [0, 1, ..., n] 。 给你一个整数 n 和一个长度为 n + 1 的整数数组 ranges ,其中 ranges[i] (下标从 0 开始)表示:如果打开点 i 处的水龙头,可以灌溉的区域为 [i - ranges[i], i + ranges[i]] 。 请你返回可以灌溉整个花园的 最少水龙头数目 。如果花园始终存在无法灌溉到的地方,请你返回 -1 。
输入:n = 5, ranges = [3,4,1,1,0,0]
输出:1
解释:
点 0 处的水龙头可以灌溉区间 [-3,3]
点 1 处的水龙头可以灌溉区间 [-3,5]
点 2 处的水龙头可以灌溉区间 [1,3]
点 3 处的水龙头可以灌溉区间 [2,4]
点 4 处的水龙头可以灌溉区间 [4,4]
点 5 处的水龙头可以灌溉区间 [5,5]
只需要打开点 1 处的水龙头即可灌溉整个花园 [0,5] 。
来源:leetcode-cn.com/problems/mi…
var minTaps = function(n, ranges) {
let land = Array.from(new Array(n).fill(0));
for (let i = 0; i < ranges.length; i++) {
let l = Math.max(i - ranges[i], 0);
let r = Math.min(i + ranges[i], n);
for (let j = l; j < r; j++) {
land[j] = Math.max(land[j], r)
}
}
let count = 0, cur = 0;
while(cur < n) {
if(land[cur] == 0) return -1;
cur = land[cur];
count++;
}
return count;
};
无重叠区间
给定一个区间的集合,找到需要移除区间的最小数量,使剩余区间互不重叠。
注意:可以认为区间的终点总是大于它的起点。区间 [1,2] 和 [2,3] 的边界相互“接触”,但没有相互重叠。
输入: [ [1,2], [2,3], [3,4], [1,3] ]
输出: 1
解释: 移除 [1,3] 后,剩下的区间没有重叠。
来源:leetcode-cn.com/problems/no…
var eraseOverlapIntervals = function(intervals) {
if (intervals.length === 0) return 0;
intervals.sort((a, b) => a[1] - b[1]);
var cnt = 1;
var end = intervals[0][1];
for(let i=1;i<intervals.length;i++) {
if(intervals[i][0] < end) {
continue;
}
end = intervals[i][1];
cnt++;
}
return intervals.length - cnt;
};
种花问题
假设你有一个很长的花坛,一部分地块种植了花,另一部分却没有。可是,花卉不能种植在相邻的地块上,它们会争夺水源,两者都会死去。 给定一个花坛(表示为一个数组包含0和1,其中0表示没种植花,1表示种植了花),和一个数 n 。能否在不打破种植规则的情况下种入 n 朵花?能则返回True,不能则返回False。
输入: flowerbed = [1,0,0,0,1], n = 1
输出: True
输入: flowerbed = [1,0,0,0,1], n = 2
输出: False
来源:leetcode-cn.com/problems/ca…
var canPlaceFlowers = function(flowerbed, n) {
let num = 0, count = 1;
for (let i = 0; i < flowerbed.length; i++) {
if(flowerbed[i] === 0) {
count++;
} else {
count = 0;
}
if(count === 3) {
num++;
count = 1;
}
}
if(count === 2) {
num++;
}
return n <= num;
};
用最少数量的箭引爆气球
在二维空间中有许多球形的气球。对于每个气球,提供的输入是水平方向上,气球直径的开始和结束坐标。由于它是水平的,所以纵坐标并不重要,因此只要知道开始和结束的横坐标就足够了。开始坐标总是小于结束坐标。 一支弓箭可以沿着 x 轴从不同点完全垂直地射出。在坐标 x 处射出一支箭,若有一个气球的直径的开始和结束坐标为 xstart,xend, 且满足 xstart ≤ x ≤ xend,则该气球会被引爆。可以射出的弓箭的数量没有限制。 弓箭一旦被射出之后,可以无限地前进。我们想找到使得所有气球全部被引爆,所需的弓箭的最小数量。 给你一个数组 points ,其中 points [i] = [xstart,xend] ,返回引爆所有气球所必须射出的最小弓箭数。
输入:points = [[10,16],[2,8],[1,6],[7,12]]
输出:2
解释:对于该样例,x = 6 可以射爆 [2,8],[1,6] 两个气球,以及 x = 11 射爆另外两个气球
来源:leetcode-cn.com/problems/mi…
var findMinArrowShots = function(points) {
if(points.length === 0) return 0;
points.sort((a, b) => a[1] - b[1]);
let pos = points[0][1];
let ans = 1;
for (let ballon of points) {
if(ballon[0] > pos) {
pos = ballon[1];
ans++;
}
}
return ans;
};
划分字母区间
字符串 S 由小写字母组成。我们要把这个字符串划分为尽可能多的片段,同一字母最多出现在一个片段中。返回一个表示每个字符串片段的长度的列表。
输入:S = "ababcbacadefegdehijhklij"
输出:[9,7,8]
解释:
划分结果为 "ababcbaca", "defegde", "hijhklij"。
每个字母最多出现在一个片段中。
像 "ababcbacadefegde", "hijhklij" 的划分是错误的,因为划分的片段数较少。
来源:leetcode-cn.com/problems/pa…
var partitionLabels = function(S) {
let res = [];
let map = new Map(), start = 0, end = 0;
for (let i = 0; i < S.length; i++) {
map[S[i]] = i;
}
for (let j = 0; j < S.length; j++) {
end = Math.max(end, map[S[j]]);
if(j === end) {
res.push(end - start + 1);
start = j + 1;
}
}
return res;
};
根据身高重建队列
假设有打乱顺序的一群人站成一个队列,数组 people 表示队列中一些人的属性(不一定按顺序)。每个 people[i] = [hi, ki] 表示第 i 个人的身高为 hi ,前面 正好 有 ki 个身高大于或等于 hi 的人。 请你重新构造并返回输入数组 people 所表示的队列。返回的队列应该格式化为数组 queue ,其中 queue[j] = [hj, kj] 是队列中第 j 个人的属性(queue[0] 是排在队列前面的人)。
输入:people = [[7,0],[4,4],[7,1],[5,0],[6,1],[5,2]]
输出:[[5,0],[7,0],[5,2],[6,1],[4,4],[7,1]]
解释:
编号为 0 的人身高为 5 ,没有身高更高或者相同的人排在他前面。
编号为 1 的人身高为 7 ,没有身高更高或者相同的人排在他前面。
编号为 2 的人身高为 5 ,有 2 个身高更高或者相同的人排在他前面,即编号为 0 和 1 的人。
编号为 3 的人身高为 6 ,有 1 个身高更高或者相同的人排在他前面,即编号为 1 的人。
编号为 4 的人身高为 4 ,有 4 个身高更高或者相同的人排在他前面,即编号为 0、1、2、3 的人。
编号为 5 的人身高为 7 ,有 1 个身高更高或者相同的人排在他前面,即编号为 1 的人。
因此 [[5,0],[7,0],[5,2],[6,1],[4,4],[7,1]] 是重新构造后的队列。
来源:leetcode-cn.com/problems/qu…
var reconstructQueue = function(people) {
let ans = [];
people.sort((a,b) => {
return a[0] === b[0] ? a[1] - b[1] : b[0] - a[0];
});
for(let i = 0 ; i < people.length; i++) {
ans.splice(people[i][1],0,people[i]);
}
return ans;
};
非递减数列
给你一个长度为 n 的整数数组,请你判断在 最多 改变 1 个元素的情况下,该数组能否变成一个非递减数列。 我们是这样定义一个非递减数列的: 对于数组中所有的 i (0 <= i <= n-2),总满足 nums[i] <= nums[i + 1]。
输入: nums = [4,2,3]
输出: true
解释: 你可以通过把第一个4变成1来使得它成为一个非递减数列。
来源:leetcode-cn.com/problems/no…
var checkPossibility = function(nums) {
let i, cnt = 0;
for (i = 0; i < nums.length; i++) {
if(nums[i] > nums[i+1]) {
if(i == 0 || nums[i - 1] <= nums[i + 1]) {
nums[i] = nums[i + 1]
} else if (nums[i - 1] > nums[i + 1]) {
nums[i + 1] = nums[i]
}
++cnt;
if( cnt > 1) {
return false;
}
}
}
return true;
};