You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
/** * @param {number[]} nums1 * @param {number} m * @param {number[]} nums2 * @param {number} n * @return {void} Do not return anything, modify nums1 in-place instead. */varmerge=function(nums1,m,nums2,n){// 两个数组对应指针letp1=0letp2=0// 这里需要提前把nums1的元素拷贝出来,要不然比较赋值后就丢失了letcpArr=nums1.splice(0,m)// 数组指针letp=0while(p1<m&&p2<n){// 先赋值,再进行+1操作nums1[p++]=cpArr[p1]<nums2[p2] ? cpArr[p1++] : nums2[p2++]}// 已经有p个元素了,多余的元素要删除,剩余的要加上if(p1<m){// 剩余元素,p1 + m + n - p = m + n - (p - p1) = m + n - p2nums1.splice(p,m+n-p, ...cpArr.slice(p1,m+n-p2))}if(p2<n){// 剩余元素,p2 + m + n - p = m + n - (p - p2) = m + n - p1nums1.splice(p,m+n-p, ...nums2.slice(p2,m+n-p1))}};
结果:
59/59 cases passed (48 ms)
Your runtime beats 100 % of javascript submissions
Your memory usage beats 64.97 % of javascript submissions (33.8 MB)
背景
本文记录刷题过程中的整个思考过程,以供参考。主要内容涵盖:
目录
Easy
67.二进制求和
题目地址
题目描述
给定两个二进制字符串,返回他们的和(用二进制表示)。
输入为非空字符串且只包含数字
1
和0
。示例:
题目分析设想
这道题又是一道加法题,所以记住下,直接转数字进行加法可能会溢出,所以不可取。所以我们需要遍历每一位来做解答。我这有两个大方向:补0后遍历,和不补0遍历。但是基本的依据都是本位相加,逢2进1即可,类似手写10进制加法。
查阅他人解法
Ⅰ.补0后遍历,先算先推
代码:
结果:
O(n)
Ⅱ.补0后遍历,按位运算
代码:
结果:
O(n)
Ⅲ.不补0遍历
代码:
结果:
O(n)
查阅他人解法
看到一些细节上的区别,我这使用
'1' | 0
来转数字,有的使用''1' - '0''
。另外还有就是初始化结果数组长度为最大长度加1后,最后判断首位是否为0需要剔除的,我这使用的是判断最后是否还要进位补1。这里还看到用一个提案中的
BigInt
类型来解决的Ⅰ.BigInt
代码:
结果:
O(1)
思考总结
通过
BigInt
的方案我们能看到,使用原生方法确实性能更优。简单说一下这个类型,目前还在提案阶段,看下面的等式基本就能知道实现原理自己写对应Hack
来实现了:虽然这种方式很友好,但是还是希望看到加法题的时候,能考虑到遍历按位处理。
69.x的平方根
题目地址
题目描述
实现
int sqrt(int x)
函数。计算并返回 x 的平方根,其中 x 是非负整数。
由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去。
示例:
题目分析设想
同样,这里类库提供的方法
Math.sqrt(x)
就不说了,这也不是本题想考察的意义。所以这里有几种方式:编写代码验证
Ⅰ.暴力法
代码:
结果:
O(n)
Ⅱ.二分法
代码:
结果:
O(log2(n))
查阅他人解法
这里看见了两个有意思的解法:
Ⅰ.幂次优化
稍微解释一下,二分法需要做乘法运算,他这里改用加减法
结果:
1017/1017 cases passed (72 ms)
Your runtime beats 98.46 % of javascript submissions
Your memory usage beats 70.66 % of javascript submissions (35.4 MB)
O(log2(n))
Ⅱ.牛顿法
算法说明:
在迭代过程中,以直线代替曲线,用一阶泰勒展式(即在当前点的切线)代替原曲线,求直线与 xx 轴的交点,重复这个过程直到收敛。
首先随便猜一个近似值
x
,然后不断令x
等于x
和a/x
的平均数,迭代个六七次后x
的值就已经相当精确了。公式可以写为
X[n+1]=(X[n]+a/X[n])/2
代码:
结果:
O(log2(n))
思考总结
这里就提一下新接触的牛顿法吧,实际上是牛顿迭代法,主要是迭代操作。由于在单根附近具有平方收敛,所以可以转换成线性问题去求平方根的近似值。主要应用场景有这两个方向:
70.爬楼梯
题目地址
题目描述
假设你正在爬楼梯。需要
n
阶你才能到达楼顶。每次你可以爬
1
或2
个台阶。你有多少种不同的方法可以爬到楼顶呢?注意:给定
n
是一个正整数。示例:
题目分析设想
这道题很明显可以用动态规划和斐波那契数列来求解。然后我们来看看其他正常思路,如果使用暴力法的话,那么复杂度将会是
2^n
,很容易溢出,但是如果能够优化成n
的话,其实还可以求解的。所以这道题我就从以下三个方向来作答:编写代码验证
Ⅰ.哈希递归
代码:
结果:
O(n)
Ⅱ.动态规划
代码:
结果:
O(n)
Ⅲ.斐波那契数列
其实斐波那契数列就可以用动态规划来实现,所以下面的代码思路很相似。
代码:
结果:
O(n)
查阅他人解法
查看题解发现这么几种解法:
Ⅰ.斐波那契公式
代码:
结果:
O(log(n))
Ⅱ.Binets 方法
算法说明:
使用矩阵乘法来得到第 n 个斐波那契数。注意需要将初始项从
fib(2)=2,fib(1)=1
改成fib(2)=1,fib(1)=0
,来达到矩阵等式的左右相等。解法参考官方题解
代码:
结果:
测试用例可以输出,提交发现超时。
Ⅲ.排列组合
代码:
结果:
O(n^2)
思考总结
这种叠加的问题,首先就会想到动态规划的解法,刚好这里又满足斐波那契数列,所以我是推荐首选这两种解法。另外通过查看他人解法学到了斐波那契公式,以及站在排列组合的角度去解,开拓了思路。
83.删除排序链表中的重复元素
题目地址
题目描述
给定一个排序链表,删除所有重复的元素,使得每个元素只出现一次。
示例:
题目分析设想
注意一下,给定的是一个排序链表,所以只需要依次更改指针就可以直接得出结果。当然,也可以使用双指针来跳过重复项即可。所以这里有两个方向:
如果是无序链表,我会建议先得到所有值然后去重后(比如通过Set)生成新链表作答。
编写代码验证
Ⅰ.直接运算
代码:
结果:
O(n)
Ⅱ.双指针法
代码:
结果:
O(n)
查阅他人解法
忘记了,这里确实还可以使用递归来作答。
Ⅰ.递归法
代码:
结果:
O(n)
思考总结
关于链表的题目一般都是通过修改指针指向来作答,区分单指针和双指针法。另外,遍历也是可以实现的。
88.合并两个有序数组
题目地址
题目描述
给定两个有序整数数组
nums1
和nums2
,将nums2
合并到nums1
中,使得num1
成为一个有序数组。说明:
nums1
和nums2
的元素数量分别为m
和n
。nums1
有足够的空间(空间大小大于或等于m + n
)来保存nums2
中的元素。示例:
题目分析设想
之前我们做过删除排序数组中的重复项,其实这里也类似。可以从这几个方向作答:
但是由于题目有限定空间都在
nums1
,并且不要写return
,直接在nums1
上修改,所以我这里主要的思路就是遍历,通过splice
来修改数组。区别就在于遍历的方式方法。编写代码验证
Ⅰ.从前往后
代码:
结果:
O(m + n)
Ⅱ.从后往前
代码:
结果:
O(m + n)
Ⅲ.合并后排序再赋值
代码:
结果:
O(m + n)
查阅他人解法
这里看到一个直接用两次
while
,然后直接用m/n
来计算下标的,没有额外空间,但是本质上也是从后往前遍历。Ⅰ.两次while
代码:
结果:
O(m + n)
思考总结
碰到数组操作,会优先考虑双指针法,具体指针方向可以由题目逻辑来决定。
(完)
The text was updated successfully, but these errors were encountered: