LeetCode #66 加一
题目描述
给定一个由整数组成的非空数组所表示的非负整数,在该数的基础上加一。 最高位数字存放在数组的首位, 数组中每个元素只存储单个数字。 你可以假设除了整数 0 之外,这个整数不会以零开头。
示例1
输入: [1,2,3],
输出: [1,2,4]
解释: 输入数组表示数字 123。
示例2
输入: [4,3,2,1],
输出: [4,3,2,2] 解释: 输入数组表示数字 4321。
方法一
自己花了30分钟写的复杂逻辑,菜实锤。
想法是先判断个位数是否进位,根据flag变量来标识,后面的数也是,
把个位数和后面的数分开来的原因是个位数是否进位是后续数的判断依据。
列举一下过程中的忽略的点吧:
<1 忽略有[9]这种情况
<2 添加元素时判断失误,当flag为true,即前一位进位时,若当前元素+1没有产生进位,忘记应该将进位的1加上
<3 忽略99这种加1后 需要多一位的情况
/**
* @param {number[]} digits
* @return {number[]}
*/
var plusOne = function(digits) {
var res = [], i=digits.length - 2, flag = false;
// 个位数+1的情况单独考虑,决定后续数, flag标志表示是否进位
if((digits[i + 1] + 1) % 10 === 0) {
// 只有一位时若产生进位
digits.length === 1 ? res.unshift(1, 0) : res.unshift(0);
flag = true;
} else {
res.unshift(digits[i+1] + 1);
flag = false;
}
while(i >= 0) {
// 前一位和当前位都进位
if(flag && (digits[i] + 1) % 10 === 0) {
res.unshift(0);
} else {
// 当前位不进位
res.unshift(flag ? (digits[i] + 1) : digits[i]);
flag = false;
}
i--;
}
// 判断元素都为9的情况
if(res[0] === 0 && res.length > 1) {
res.unshift(1);
}
return res;
};
方法二 (题解-巧妙法)
考虑数字+1后可能出现的情况
<1 无进位,类似5,6
<2 中间位产生进位 129,499
<3 最高位进位 9,99,999
/**
* @param {number[]} digits
* @return {number[]}
*/
var plusOne = function(digits) {
for(var i=digits.length-1; i>=0; i--) {
digits[i]++;
// 处理进位时的情况
digits[i] = digits[i] % 10;
// 如果+1 之后没有产生进位,则说明运算完毕。
if(digits[i] !== 0) return digits;
}
// 处理[9]这种情况
digits = [1, ...digits];
return digits;
};
LeetCode #88 合并两个有序数组
题目描述
给你两个有序整数数组 nums1 和 nums2,请你将 nums2 合并到 nums1 中,使 num1 成为一个有序数组。
说明
初始化 nums1 和 nums2 的元素数量分别为 m 和 n 。 你可以假设 nums1 有足够的空间(空间大小大于或等于 m + n)来保存 nums2 中的元素。
示例1
输入: nums1 = [1,2,3,0,0,0], m = 3. nums2 = [2,5,6], n = 3
输出: [1,2,2,3,5,6]
方法一
暴力合并排序
不是最佳方案,忽略了两个数组都是有序数组
/**
* @param {number[]} nums1
* @param {number} m
* @param {number[]} nums2
* @param {number} n
* @return {void} Do not return anything, modify nums1 in-place instead.
*/
var merge = function(nums1, m, nums2, n) {
nums1.splice(m, n, ...nums2);
nums1.sort((a, b) => {
return a - b;
})
};
方法二 (双指针 正向)
合并两个有序数组
遍历比较两个数组元素大小,决定指针如何移动
比如[1, 2, ...] m=2 简称数组m
[0, 4, 5] n=3 简称数组n
先比较1与0的大小,1 > 0,则新数组当前位置为0,n数组指针往后移位
比较1与4的大小,4 > 1 则新数组第二位为1,m数组指针往后移位
比较4与2的大小,4 > 2, m数组指针往后移位,第三位为2
移位后超出m长度,
...依次类推
当m或n移位到最后一位时结束,考虑极端情况,此时可能出现两种情况
1. m中的数很大,n中的数都排在前面
2. n中的数很大,m中的数都排在前面,n的指针还没动就结束循环了,
!!此时需要将n中剩余元素加到m数组后面
/**
* @param {number[]} nums1
* @param {number} m
* @param {number[]} nums2
* @param {number} n
* @return {void} Do not return anything, modify nums1 in-place instead.
*/
var merge = function(nums1, m, nums2, n) {
// p1, p2, p分别为nums,nums2, nums指针
var p1=p2=p=0, nums = [...nums1];
while(p2 < n && p<m) {
// nums1中元素更大,p2指针后移,否则p指针后移
nums1[p1++] = nums[p] > nums2[p2] ? nums2[p2++] : nums[p++];
}
// 考虑多余元素的情况
if(p2<n) {
// 此时nums中元素已经都排序,nums2中多余元素都是大于nums中元素
// 添加到数组nums1最后
nums1.splice(p1, nums1.length, ...nums2.slice(p2));
}
if(p < m) {
nums1.splice(p1, nums1.length, ...nums.slice(p, m))
}
};
方法二 (双指针 逆向)
双指针正向循环的时候,开辟了一块内存空间来存储nums1的副本nums 如果从逆向开始,也就是从大到小去合并排序 因为nums1后面是没有元素的,可以直接替换,减少了存储空间
var merge = function(nums1, m, nums2, n) {
var p1=m-1, p2=n-1, p=nums1.length - 1;
while(p1 >= 0 && p2 >= 0) {
nums1[p--] = nums1[p1] > nums2[p2] ? nums1[p1--] : nums2[p2--];
}
// 处理nums2剩余元素
if(p2 >= 0) {
nums1.splice(0, p+1, ...nums2.slice(0, p2 + 1))
}
// nums1剩余元素 都是比nums2小的,且已经排好序,不用处理
}