前端重拾算法数据结构一个月(2)

122 阅读5分钟

前言

昨天复习了算法复杂度以及基本的数据结构。今天继续来刷题。(说实话下班回来以后乏乏的,但是加油打工人!!)

第二天

延续昨天的题目数。

第四题

剑指 Offer 20. 表示数值的字符串

请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。 数值(按顺序)可以分成以下几个部分:

  1. 若干空格
  2. 一个小数或者整数
  3. (可选)一个 'e' 或 'E' ,后面跟着一个整数
  4. 若干空格

小数(按顺序)可以分成以下几个部分:

  1. (可选)一个符号字符('+' 或 '-')
  2. 下述格式之一:
  3. 至少一位数字,后面跟着一个点 '.'
  4. 至少一位数字,后面跟着一个点 '.' ,后面再跟着至少一位数字
  5. 一个点 '.' ,后面跟着至少一位数字

整数(按顺序)可以分成以下几个部分:

  1. (可选)一个符号字符('+' 或 '-')
  2. 至少一位数字

示例:

输入:s="0"
输出:true
输入:s="  .1  "
输出:true

提示:s仅含英文字母(大写和小写),数字(0-9),加号 '+' ,减号 '-' ,空格 ' ' 或者点 '.' 。

思路: 这题给我的感觉就是,好复杂TAT,第一反应就是用正则表达式去筛选。老实讲,这道题有点难到我了,特殊情况有好多,不过也正体现出我的正则表达式掌握得不是很好。还是根据题目中对数值的描述来一点一点写:首先让前后可以有若干的空格。然后接着有小数或整数,这都是必有的。接着再写可选的e|E,但重要的是e|E后面必须跟着一个整数。

function isNumber(s: string): boolean {
    return /^\s*[\+\-]?((\d+|\.\d+|\d+\.\d+)(\.?(e|E)[\+\-]?\d+)?|\d+\.((e|E)[\+\-]?\d+)?)\s*$/.test(s)
};

第五题

剑指 Offer 24. 反转链表

定义一个函数,输入一个链表的头节点,反转该链表并输出反转后链表的头节点。 示例:

输入:1->2->3->4->5->NULL
输出:5->4->3->2->1->NULL

思路: 这题要返回的是反转后链表的【头节点】。所以必须做出一个完整的链表了。首先需要let一个变量来带路,让我可以一直沿着原链表走,我这里用的是p2,然后需要let一个变量来作为head新的next。

function reverseList(head: ListNode | null): ListNode | null {
    if(head===null) return null
    let p1 = null
    let p2 = head.next
    while(head!==null){
    head.next = p1 //改变head的next指向
    p1 = head      //让p1向后移
    head = p2      //让head向后移
    p2 = p2===null?null:p2.next  //让p2向后移,但是p2到null的时候,head还有一个值,所以需要判                                  //断一下,因为null没有next
    }
    return p1
};

第六题

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

定义栈的数据结构,请在该类型中实现一个能够得到栈的最小元素的 min 函数在该栈中,调用 min、push 及 pop 的时间复杂度都是 O(1)。 示例:

MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.min();   --> 返回 -3.
minStack.pop();
minStack.top();      --> 返回 0.
minStack.min();   --> 返回 -2.

思路: 一开始想的是要整一个map来存数组,这样查值的时候时间复杂度就可以是O(1),但是写到一半发现,想多余了哈哈,js(ts)实在是个神奇的语言。

class MinStack {
    stack:number[]
    constructor(stack:number[]) {
        this.stack = stack?stack:[]
    }

    push(x: number): void {
        this.stack.push(x)
    }

    pop(): void {
        this.stack.pop()
    }

    top(): number {
        return this.stack[this.stack.length-1]
    }

    min(): number {
        return Math.min.apply(Math,this.stack) //使用Math查找数组中的最小值
    }
}

不过出于好奇心,还是去看了一眼题解,使用两个数组,第二个数组是判断新来的数字是否小于等于数组中的最小值,如果是的话才加入,这样数组最后面的那个数就是最小的了。

第七题

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

字符串的左旋转操作是把字符串前面的若干个字符转移到字符串的尾部。请定义一个函数实现字符串左旋转操作的功能。比如,输入字符串"abcdefg"和数字2,该函数将返回左旋转两位得到的结果"cdefgab"。 示例:

输入: s = "abcdefg", k = 2
输出: "cdefgab"

思路: 先设置两个空数组,将字符串拆分成数组,将下标小于输入数字的项存于一个二号数组中,将不需要旋转的项存于一号数组中。再将一二号数组按顺序,join回字符串再拼接起来得到答案。

function reverseLeftWords(s: string, n: number): string {
    if(s.length===n) return s
    const firstArr:string[] = []
    const secondArr:string[] = []
    s.split('').forEach((item,index)=>{
        if(index<n){
            secondArr.push(item)
        }else{
            firstArr.push(item)
        }
    })
    return firstArr.join('')+secondArr.join('')
};

第八题

剑指 Offer 59 - I. 滑动窗口的最大值

示例:

输入: nums = [1,3,-1,-3,5,3,6,7], 和 k = 3
输出: [3,3,5,5,6,7] 

思路: 遍历nums,下标到k之前,都得把所有数字存到一个kArr数组中,到时候方便比较最大值,当下标达到k-1时,就可以开始向最终要返回的数组中push最大值了。接着后面的遍历都得把kArr的头一项去除掉,再向其中push新数据。

function maxSlidingWindow(nums: number[], k: number): number[] {
    if(nums.length===0) return []
    const kArr:number[] = []
    const result:number[] = []
    nums.forEach((item,index)=>{
        if(index>=k){
            kArr.shift()
        }
        kArr.push(item)
        if(index>=k-1){
            result.push(Math.max.apply(Math,kArr))
        }
    })
    return result
};

第八题

剑指 Offer 59 - II. 队列的最大值

请定义一个队列并实现函数max_value得到队列里的最大值,要求函数max_valuepush_backpop_front的均摊时间复杂度都是O(1)。 若队列为空,pop_frontmax_value需要返回 -1。 示例:

输入: ["MaxQueue","push_back","push_back","max_value","pop_front","max_value"]
      [[],[1],[2],[],[],[]]
输出: [null,null,null,2,1,2]

思路: 突然想起,数组用shift()就可以实现队列先进先出了,之前还傻傻的用两个数组去推来推去QAQ。不过也是学习它的思维嘛,有益有益。所以用ts写就是简单粗暴的:

class MaxQueue {
    line:number[]
    constructor(line:number[]) {
        this.line = line?line:[]
    }

    max_value(): number {
        if(this.line.length===0) return -1
        return Math.max.apply(Math,this.line)
    }

    push_back(value: number): void {
        this.line.push(value)
    }

    pop_front(): number {
        if(this.line.length===0) return -1
        return this.line.shift()
    }
}

哇塞有点晚了,留一题明天再做吧。然后明天就可以进入动态规划部分了。

代码敲多了一定要起来走走喝水,还有一定要温故而知新。