感觉关于JavaScript的题解不太多,所以就写一个,给自己总结用。
https://www.programmercarl.com/
>>
位运算移动,因为直接/2会产生小数mid+1
和mid-1
left+(right-left)>>1
var search = function(nums, target) {
let left=0,right=nums.length-1;
let mid=(left+right)>>1;
while(left<=right){
if(nums[mid]===target){
return mid;
}else{
if(nums[mid]<target){
left=mid+1;
}else{
right=mid-1;
}
}
mid=(left+right)>>1;
}
return -1;
};
var removeElement = function(nums, val) {
// i>=j
let i=0,j=0;
for(;i<nums.length;i++){
if(nums[i]!=val){
nums[j++]=nums[i];
}
}
return j;
};
var sortedSquares = function(nums) {
// 非递减:递增有相同
let n=nums.length;
let ans=new Array(n).fill(0);
for(let i=0,j=n-1,k=n-1;i<=j;k--){
let ii=nums[i]*nums[i];
let jj=nums[j]*nums[j];
if(ii>=jj){
ans[k]=ii;i++;
}else{
ans[k]=jj;j--;
}
}
return ans;
};
简化代码:
var sortedSquares = function(nums) {
// 平方后,两边大,中间小,涵盖所有情况
let i=0,j=nums.length-1;
let ans=new Array()
while(i<=j){
if(nums[i]**2>=nums[j]**2){
ans.push(nums[i++]**2);
}else{
ans.push(nums[j--]**2);
}
}
return ans.reverse()
};
ans=min(ans,当前长度)
(于是会保存所有长度的最小长度),然后另l++var minSubArrayLen = function(target, nums) {
const n=nums.length;
let l=0,r=0,sum=0,ans=n+1;
while(r<n){
sum+=nums[r++];
while(sum>=target){
// 让窗口变小:左闭右开
if(r-l<ans) ans=r-l;
sum-=nums[l++];
}
}
if(ans===n+1) ans=0;
return ans;
};
或:相当于把上述代码中,窗口缩小的步骤拆出来。更直观,但代码没有上述的简洁。
var minSubArrayLen = function(target, nums) {
let i=0,j=0;
let sum=nums[0],ans=100001;
while(i<nums.length&&j<nums.length){
if(sum>=target){
ans=Math.min(ans,j-i+1);
if(i<j){
i++;sum-=nums[i-1];
}else if(i==j){
// 最优的答案
return 1;
}
}else{
j++;sum+=nums[j];
}
}
return ans===100001?0:ans;
};
var generateMatrix = function (n) {
// 二维数组
let ans = new Array(n).fill(0).map(() => new Array(n).fill(0));
let x = 0, y = -1;
let now = 1;
while (now <= n * n) {
// 右
while (y + 1 < n && ans[x][y + 1] === 0) {
ans[x][y + 1] = now++;
y++;
}
if (now > n * n) break;
// 下
while (x + 1 < n && ans[x + 1][y] === 0) {
ans[x + 1][y] = now++;
x++;
}
if (now > n * n) break;
// 左
while (y - 1 >= 0 && ans[x][y - 1] === 0) {
ans[x][y - 1] = now++;
y--;
}
if (now > n * n) break;
// 上
while (x - 1 >= 0 && ans[x - 1][y] === 0) {
ans[x - 1][y] = now++;
x--;
}
}
return ans;
};
都是和“主要题目”相似的题目。
i<=j
j i
,此时跳出循环,i为答案ij 目标值
,此时i++,跳出循环,为答案var searchInsert = function(nums, target) {
let n=nums.length-1;
if(target>nums[n]){
return n+1;
}
if(target<nums[0]){
return 0;
}
let i=0,j=n;
let mid=(i+j)>>1;
while(i<=j){
if(nums[mid]===target){
return mid;
}
if(nums[mid]>target){
j=mid-1;
}else{
i=mid+1;
}
mid=(i+j)>>1;
}
// 走到这里说明没有且i>j
return i;
};
二刷:
var searchInsert = function(nums, target) {
// 返回第一个>=target的值
let l=0,r=nums.length-1;
// 特判
if(target<nums[l]) return l;
if(target>nums[r]) return r+1;
let mid;
while(l<=r){
mid=(l+r)>>1;
if(nums[mid]===target){
return mid;
}
else{
if(nums[mid]<target){
l=mid+1;
}else{
r=mid-1;
}
}
}
return l;
};
一道细节比较多的题:
最后一个小于目标的位置
分别对应getLeft
和getRight
。
注意:
target是否在范围内
target是否存在
getLeft
:
const getLeft=function(nums,target){
let l=0,r=nums.length-1;
let mid=(l+r)>>1;
let ans=-2;
while(l<=r){
mid=(l+r)>>1;
if(nums[mid]>=target){
r=mid-1;
// 大于等于都要变,留下的是最右边的小于
ans=r;
}else{
l=mid+1;
}
}
return ans;
}
getRight
:
// 找右边界:第一个大于target的
const getRight=function(nums,target){
let l=0,r=nums.length-1;
let mid=(l+r)>>1;
let ans=-2;
while(l<=r){
mid=(l+r)>>1;
if(nums[mid]>target){
r=mid-1;
}else{
l=mid+1;
// 小于等于都要变,最后留下的是最左边的大于
ans=l;
}
}
return ans;
}
总体代码:
var searchRange = function(nums, target) {
// 找左边界:最后一个小于target的
const getLeft=function(nums,target){
let l=0,r=nums.length-1;
let mid=(l+r)>>1;
let ans=-2;
while(l<=r){
mid=(l+r)>>1;
if(nums[mid]>=target){
r=mid-1;
// 大于等于都要变,留下的是最右边的小于
ans=r;
}else{
l=mid+1;
}
}
return ans;
}
// 找右边界:第一个大于target的
const getRight=function(nums,target){
let l=0,r=nums.length-1;
let mid=(l+r)>>1;
let ans=-2;
while(l<=r){
mid=(l+r)>>1;
if(nums[mid]>target){
r=mid-1;
}else{
l=mid+1;
// 小于等于都要变,最后留下的是最左边的大于
ans=l;
}
}
return ans;
}
let left=getLeft(nums,target);
let right=getRight(nums,target);
// 范围外
if(left===-2||right===-2){
return [-1,-1]
}
// 存在
if(right-left>1) {
return[left+1,right-1];
}
// 不存在
return [-1,-1]
};
直接找第一个和最后一个target也可以:但感觉上面的方法边界的差异感强一些,更好理解。
var searchRange = function(nums, target) {
// 找左边界:最后一个小于target的
const getLeft=function(nums,target){
let l=0,r=nums.length-1;
let mid=(l+r)>>1;
let ans=-2;
while(l<=r){
mid=(l+r)>>1;
if(nums[mid]>=target){
r=mid-1;
// 大于等于都要变,留下的是第一个target
ans=r+1;
}else{
l=mid+1;
}
}
return ans;
}
// 找右边界:第一个大于target的
const getRight=function(nums,target){
let l=0,r=nums.length-1;
let mid=(l+r)>>1;
let ans=-2;
while(l<=r){
mid=(l+r)>>1;
if(nums[mid]>target){
r=mid-1;
}else{
l=mid+1;
// 小于等于都要变,最后留下的是最后一个target
ans=l-1;
}
}
return ans;
}
let left=getLeft(nums,target);
let right=getRight(nums,target);
console.log(left,right)
// 范围外
if(left===-2||right===-2){
return [-1,-1]
}
// 存在
if(right-left>=0) {
return[left,right];
}
// 不存在
return [-1,-1]
};
另一种更简单的判断是否存在的方式:
if(nums[l]===target) return [l,r];
else return [-1,-1];
总体:
var searchRange = function(nums, target) {
var getLeft=function(nums,target){
let l=0,r=nums.length-1;
let mid,ans;
while(l<=r){
mid=(l+r)>>1;
if(nums[mid]>=target){
r=mid-1;
// 每次遇到>=target时都更新ans为mid-1
// 则最后一个ans为第一个target-1
ans=r;
}else{
l++;
}
}
return ans;
}
var getRight=function(nums,target){
let l=0,r=nums.length-1;
let mid,ans;
while(l<=r){
mid=(l+r)>>1;
if(nums[mid]<=target){
l=mid+1;
ans=l;
}else{
r--;
}
}
return ans;
}
let l=getLeft(nums,target)+1;
let r=getRight(nums,target)-1;
if(nums[l]===target) return [l,r];
else return [-1,-1];
};
var mySqrt = function(x) {
let l=0,r=47000;
let ans,mid;
while(l<=r){
mid=(l+r)>>1;
// 小于等于都要存,最后保存的是最近的小于或直接等于
if(mid*mid<=x){
ans=mid;
l=mid+1;
}else {
r=mid-1;
}
}
return ans;
};
var isPerfectSquare = function(num) {
let l=0,r=47000;
let mid,ans;
while(l<=r){
mid=(l+r)>>1;
if(mid*mid<=num){
ans=mid;
l=mid+1;
}else{
r=mid-1;
}
}
if(ans*ans===num) return true;
else return false;
};
https://leetcode.cn/problems/remove-duplicates-from-sorted-array/
var removeDuplicates = function(nums) {
let n=nums.length-1;
let i=1,j=0;
for(;i<=n;i++){
if(nums[i]!=nums[j]){
nums[++j]=nums[i];
}
}
return j+1;
};
var moveZeroes = function(nums) {
let n=nums.length-1;
let i=0,j=0;
for(;i<=n;i++){
if(nums[i]){
nums[j++]=nums[i];
}
}
for(;j<=n;j++){
nums[j]=0;
}
return nums;
};
var backspaceCompare = function(s, t) {
let ss='',tt='';
let cnt=0;
for(let i=s.length-1;i>=0;i--){
if(cnt){
if(s[i]==='#'){
cnt++;
}else{
cnt--;
}
}else{
if(s[i]==='#'){
cnt++;
}else{
ss+=s[i];
}
}
}
cnt=0;
for(let i=t.length-1;i>=0;i--){
if(cnt){
if(t[i]==='#'){
cnt++;
}else{
cnt--;
}
}else{
if(t[i]==='#'){
cnt++;
}else{
tt+=t[i];
}
}
}
// console.log(ss,tt)
if(ss===tt) return true;
else return false;
};
简化代码:
var backspaceCompare = function(s, t) {
let ss='',cnt=0;
for(let i=s.length-1;i>=0;i--){
if(s[i]==='#') cnt++;
else{
if(cnt) cnt--;
else ss+=s[i];
}
}
let tt='';cnt=0;
for(let i=t.length-1;i>=0;i--){
if(t[i]==='#') cnt++;
else{
if(cnt) cnt--;
else tt+=t[i];
}
}
if(ss===tt) return true;
else return false;
};
var totalFruit = function(fruits) {
let n=fruits.length,ans=0;
// 要用map记录数量,而不只是是否存在
let map=new Map();
let l=0,r=0;
for(r=0;r<n;r++){
map.set(fruits[r],(map.get(fruits[r])||0)+1);
while(map.size>2){
map.set(fruits[l],map.get(fruits[l])-1);
if(map.get(fruits[l])===0){
map.delete(fruits[l]);
}
l++;
}
ans=Math.max(ans,r-l+1)
}
return ans;
};
写过一个错误的代码,它在缩小滑动窗口时使用的是if(map.size>2)
,但是它能通过所有的样例。
经过一番思考发现,if判断会使得每次r++时有l++,也就是说,此时的map大小不变。因此不会对最后的ans有影响(题目所求的是ans的最大值)。但是这样的话map将不会只有2种水果。
在此代码中,想要让ans继续变大,只有在每次r++时map.size<=2才行,这样才不会l++。
举个例子,样例[1,2,1,3,3]
.
[1,2,1] 时,有最大数量,3
遇到3时,l++,此时篮子里是[2,1,3]。
篮子里有3种水果,但r-l+1 还是3
(当然,这里应该是2,不过这里是3不会影响最后的结果)
var totalFruit = function(fruits) {
const n=fruits.length;
const map=new Map();
let l=0,r=0,ans=0;
for(;r<n;r++){
// 放新的
map.set(fruits[r],(map.get(fruits[r])||0)+1);
if(map.size>2){
map.set(fruits[l],map.get(fruits[l])-1);
if(map.get(fruits[l])===0){
map.delete(fruits[l])
}
l++;
}
ans=Math.max(ans,r-l+1);
}
return ans;
};
注意:这里跳出循环的条件与59不同。
这里是获取数字,因此cnt从0开始,每获取一个就+1,当获取到
n*m
个是结束。
59是填入数字,因此cnt从1开始填,填完就+1,当cnt>n*m
时说明第n*m
个刚好填完,跳出循环。
var spiralOrder = function (matrix) {
let ans = new Array()
let i = 0, j = -1, cnt = 0, sum = matrix.length * matrix[0].length;
while (cnt < sum) {
// 右
while (j + 1 < matrix[0].length && matrix[i][j + 1] != 101) {
ans.push(matrix[i][j + 1])
matrix[i][j + 1] = 101
j++; cnt++;
}
if (cnt >= sum) break;
// 下
while (i + 1 < matrix.length && matrix[i + 1][j] != 101) {
ans.push(matrix[i + 1][j])
matrix[i + 1][j] = 101
i++; cnt++;
}
if (cnt >= sum) break;
// 左
while (j - 1 >= 0 && matrix[i][j - 1] != 101) {
ans.push(matrix[i][j - 1])
matrix[i][j - 1] = 101
j--; cnt++;
}
if (cnt >= sum) break;
// 上
while (i - 1 >= 0 && matrix[i - 1][j] != 101) {
ans.push(matrix[i - 1][j])
matrix[i - 1][j] = 101
i--; cnt++;
}
}
return ans;
};