剑指offer-JavaScript

这篇博客探讨了数据结构中的栈和队列实现,如用两个栈实现队列,以及包含min函数的栈。接着介绍了链表操作,包括从尾到头打印链表、反转链表和复杂链表复制。在字符串处理方面,讲解了替换空格和左旋转字符串的方法。此外,还涉及查找算法,如在排序数组中查找数字和寻找缺失数字。文章通过实例解析了各种算法的思路和优化技巧。
摘要由CSDN通过智能技术生成

一、栈与队列

1. 用两个栈实现队列

剑指 Offer 09. 用两个栈实现队列

总是出现这样的问题,对数组进行增删查改的过程中,因为数组是动态变化的,所以需要提前保留length的长度,预先定义好个数。否则会出问题,而且还会觉得自己是写的是对的。

题解感悟:其实数据不需要来回倒,因为右边的stack有已完成倒序的元素,只需要从左到右倒。

2. 包含min函数的栈

剑指 Offer 30. 包含min函数的栈

看完题目之后准备用一个min作为标记,直接记录栈内的最小元素。后来看了题解,发现这样的想法不可行,如果那个最小的元素被pop出去了,但是min记录却不能回退了,所以需要使用一个数组来记录历时最小值,这样可以随时后退。题解用的是辅助栈,但是辅助数组应该也可以。

特别注意:当push一个与当前最小值相同的节点,该最小值也需要同时push到辅助栈里。

二、链表(简单)

1. 从尾到头打印链表

剑指 Offer 06. 从尾到头打印链表

利用辅助的空间(比如说栈、数组),这样的想法还挺简单。用递归就很绝,唉,递归和DP一直是我的短板,无语。

2. 反转链表

剑指 Offer 24. 反转链表

写题的时候大概知道,需要暂存一下当前节点的next,并且还需要记录当前节点,以便于之后朝着前面指的时候找的到数据。(我的脑子:&!*&$%)

题解:先暂存后继节点tmp,然后修改链表节点的指向,使用pre暂存当前节点,访问下一节点。

3. 复杂链表的复制

剑指 Offer 35. 复杂链表的复制

没解,这题有点(unexpectedly)的复杂。

三、字符串(简单)

1. 替换空格

剑指 Offer 05. 替换空格

s.replace(/ /g, "%20");

或许需要复习一下正则表达式呢!正则表达式不要背

2. 左旋转字符串

剑指 Offer 58 - II. 左旋转字符串

var ns1 = s.substring(n);
var ns2 = s.slice(0, n);

四、查找算法(简单)

1. 数组中重复的数字

剑指 Offer 03. 数组中重复的数字

优秀的解法(原地交换/而非暴力)是将nums[index]的值交换到数组中所对应的位置,比如说这里的2,就要被交换到nums[2]上,但是这题不能用for循环解,因为不能保证当前交换得到的值的index是对应的,所以要用while循环,保证每次当前的值是一一对应的。

2. 在排序数组中查找数字

剑指 Offer 53 - I. 在排序数组中查找数字 I

利用二分找前后数字的边界,当找last position的时候需要(i+j+1)>>1,这个题解的代码很清楚。不知道为什么现在题解的代码总是很短,很简洁。逻辑写清楚难道不是更容易理解吗?又不是在比谁的代码短???

/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number}
 */
var search = function(nums, target) {
    if(nums.length == 0){
        return 0;
    }
    var start = findFirstPosition(nums, target);
    if(start == -1){
        return 0;
    }
    var end = findLastPosition(nums, target);
    if(end == -1){
        return 0;
    }
    return end-start+1;
};

function findFirstPosition(nums, target){
    var i = 0, j = nums.length-1;
    while(i < j){
        let mid = (i+j)>>1;
        if(nums[mid] < target){
            i = mid+1;
        }else if(nums[mid] == target){
            j = mid;
        }else if(nums[mid] > target){
            j = mid-1;
        }
    }
    if(nums[i] == target){
        return i;
    }else{
        return -1;
    }
}

function findLastPosition(nums, target){
  var i = 0, j = nums.length-1;
    while(i < j){
        let mid = (i+j+1)>>1;
        if(nums[mid] < target){
            i = mid+1;
        }else if(nums[mid] == target){
            i = mid;
        }else if(nums[mid] > target){
            j = mid-1;
        }
    }
    if(nums[j] == target){
        return j;
    }else{
        return -1;
    }
}

2. 0~n-1中缺失的数字

剑指 Offer 53 - II. 0~n-1中缺失的数字

比上一题简单,只需要一次二分查找就可以了。

五、查找算法(中等)

1. 二维数组的查找

剑指 Offer 04. 二维数组中的查找

找到一个点,它的两个方向(可以是左-下/或者是右-上)一边增大,一边减小,类似于二叉搜索树,这两个点就是左下角和右上角,可以选择从这两个点开始进行搜索。

2. 旋转数组的最小数字

剑指 Offer 11. 旋转数组的最小数字

首先需要分析一下题目:可能存在重复元素的有序数组。重复这两个值让这道题变得没有那么简单了。还是想到要用二分去做,但是有一个问题,如何收缩二分的区间,有三种情况:

 需要证明当nums[m] == nums[j]的时候,j=j-1可以有效的缩小区间范围。

  1. [1, 0, 1, 1, 1]:旋转点 x = 1,m = 2, 当执行 j = j - 1的时候,旋转点还落在区间里。
  2. [1, 1, 1, 2, 3, 1] :旋转点 x = 4,m = 2,当执行 j = j - 1的时候,旋转点丢失。但这无所谓,因为之前的nums[m] == nums[j],虽然把后面的1丢掉了,但是在前面还有保留,相当于在数组[[1, 1, 1, 2, 3]继续寻找最小值,也总能找到1

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值