剑指Offer3-12(10道题)

本文仅供自己复习使用

以下的题目均采用多解法方式

1、剑指 Offer 03. 数组中重复的数字
在这里插入图片描述
a、用集合set
用集合应该是最好想到的一个方法

	/**
	 * @param {number[]} nums
	 * @return {number}
	 */
	var findRepeatNumber = function(nums) {
	    let set = new Set()
	    for(let i = 0; i < nums.length; i++) {
	        if(set.has(nums[i])) {
	            return nums[i]
	        } else {
	            set.add(nums[i])
	        }
	    }
	};

b、原地放置
这个的话就是因为下标和值刚好能对应上,所以就需要通过交换两个值来看是否有相同的

	/**
	 * @param {number[]} nums
	 * @return {number}
	 */
	var findRepeatNumber = function(nums) {
	    for(let i = 0; i < nums.length; i++) {
	        while(nums[i] !== i) {
	            if(nums[nums[i]] !== nums[i]) {
	                // 这里都要用temp
	                let temp = nums[i]
	                // 毕竟这一步更改了nums[i]
	                nums[i] = nums[temp]
	                // 这里就拿不到原来的nums[i]
	                nums[temp] = temp
	            } else {
	                return nums[i]
	            }
	        }
	    }
	};

c、排序

	/**
	 * @param {number[]} nums
	 * @return {number}
	 */
	var findRepeatNumber = function(nums) {
	    nums = nums.sort()
	    let pre = nums[0]
	    for(let i = 1; i < nums.length; i++) {
	        if(pre === nums[i]) {
	            return pre
	        }
	        pre = nums[i]
	    }
	};

2、剑指 Offer 04. 二维数组中的查找
在这里插入图片描述
a、使用js的Array.prototype.flat
通过flat方法,将多维数组变成一维,然后通过indexOf找

	/**
	 * @param {number[][]} matrix
	 * @param {number} target
	 * @return {boolean}
	 */
	var findNumberIn2DArray = function(matrix, target) {
	    return matrix.flat().indexOf(target) !== -1
	};

b、通过遍历找
不多说,就是暴力

	/**
	 * @param {number[][]} matrix
	 * @param {number} target
	 * @return {boolean}
	 */
	var findNumberIn2DArray = function(matrix, target) {
	    for(let i = 0; i < matrix.length; i++) {
	        if(matrix[i].indexOf(target) !== -1) {
	            return true
	        }
	    }
	    return false
	};

c、找到合适的位置开始改变行和列
这道题有一个位置很重要,也就是左下角,如果目标比左下角大就可以列+1,如果目标比左下角小就是行-1

	/**
	 * @param {number[][]} matrix
	 * @param {number} target
	 * @return {boolean}
	 */
	var findNumberIn2DArray = function(matrix, target) {
	    let row = matrix.length - 1, col = 0
	    while(row >= 0 && col < matrix[0].length) {
	        if(matrix[row][col] < target) {
	            col++
	        } else if(matrix[row][col] > target) {
	            row--
	        } else {
	            return true
	        }
	    }
	    return false
	};

3、剑指 Offer 05. 替换空格
在这里插入图片描述
a、正则表达直接替换

	/**
	 * @param {string} s
	 * @return {string}
	 */
	var replaceSpace = function(s) {
	    return s.replace(/ /g, '%20')
	};

b、先切分,再合并

	/**
	 * @param {string} s
	 * @return {string}
	 */
	var replaceSpace = function(s) {
	    return s.split(' ').join('%20')
	};

c、暴力循环

	/**
	 * @param {string} s
	 * @return {string}
	 */
	var replaceSpace = function(s) {
	    let res = ''
	    for(let i = 0; i < s.length; i++) {
	        if(s[i] === ' ') {
	            res += '%20'
	        } else {
	            res += s[i]
	        }
	    }
	    return res
	};

4、剑指 Offer 06. 从尾到头打印链表
在这里插入图片描述
a、插队的队列
这个很好想到

	/**
	 * @param {ListNode} head
	 * @return {number[]}
	 */
	var reversePrint = function(head) {
	    let res = []
	    while(head !== null) {
	        res.unshift(head.val)
	        head = head.next
	    }
	    return res
	};

b、回溯
说白了就是递归,先弄到最里面然后再出来
这里要明确,进入到最里面后返回值是[],然后通过给这个数组逐步的加数据

	/**
	 * @param {ListNode} head
	 * @return {number[]}
	 */
	var reversePrint = function(head) {
	    let find = function(head) {
	        if(head === null) {
	            return []
	        }
	        let res = find(head.next)
	        res.push(head.val)
	        return res
	    }
	    return find(head)
	};

5、剑指 Offer 07. 重建二叉树
在这里插入图片描述
a、递归
这个很好想,其实就是之前做过的,详见算法总结

	/**
	 * @param {number[]} preorder
	 * @param {number[]} inorder
	 * @return {TreeNode}
	 */
	var buildTree = function(preorder, inorder) {
	    let getTree = function(preorder, inorder) {
	        if(preorder.length === 0 || inorder.length === 0) {
	            return null
	        }
	        let root = preorder.shift()
	        let index = inorder.indexOf(root)
	        let tree = new TreeNode(root)
	        let left = getTree(preorder, inorder.slice(0, index))
	        let right = getTree(preorder, inorder.slice(index + 1))
	        tree.left = left
	        tree.right = right
	        return tree
	    }
	    return getTree(preorder, inorder)
	};

6、剑指 Offer 09. 用两个栈实现队列
在这里插入图片描述
这道题不难,问题就在于读懂题目,因为这道题的题意是用两个后进先出的栈实现先进先出的队列

	var CQueue = function() {
	    this.stack1 = []
	    this.stack2 = []
	};
	
	/** 
	 * @param {number} value
	 * @return {void}
	 */
	CQueue.prototype.appendTail = function(value) {
	    this.stack1.push(value)
	};
	
	/**
	 * @return {number}
	 */
	CQueue.prototype.deleteHead = function() {
	    if(this.stack2.length !== 0) {
	        return this.stack2.pop()
	    }
	
	    while(this.stack1.length > 0) {
	        this.stack2.push(this.stack1.pop())
	    }
	
	    return this.stack2.length !== 0 ? this.stack2.pop() : -1
	};
	
	/**
	 * Your CQueue object will be instantiated and called as such:
	 * var obj = new CQueue()
	 * obj.appendTail(value)
	 * var param_2 = obj.deleteHead()
	 */

7、剑指 Offer 10- I. 斐波那契数列
在这里插入图片描述
斐波拉契其实最简单能想到的就是递归,但是递归的话会超时,所以这里将前两个存起来(相当于dp了)

	/**
	 * @param {number} n
	 * @return {number}
	 */
	var fib = function(n) {
	    let pre = 0, after = 1
	    if(n < 2) {
	        return n
	    }
	    let res = 0
	    for(let i = 2; i <= n; i++) {
	        res = (pre + after) % (1e9 + 7)
	        let temp = after
	        after = res
	        pre = temp
	    }
	    return res
	};

8、剑指 Offer 10- II. 青蛙跳台阶问题
在这里插入图片描述
动态规划,不多说

	/**
	 * @param {number} n
	 * @return {number}
	 */
	var numWays = function(n) {
	    let dp = new Array(n + 1).fill(0)
	    dp[0] = 1, dp[1] = 1
	    for(let i = 2; i < n + 1; i++) {
	        dp[i] = (dp[i - 1] + dp[i - 2]) % (1e9 + 7)
	    }
	    return dp[n]
	};

9、剑指 Offer 11. 旋转数组的最小数字
在这里插入图片描述
a、类似单调栈,找最突兀的
毕竟是把递增序列的前几个放最后面,那么最小的一定比前一个元素小(有点类似单调栈)

	/**
	 * @param {number[]} numbers
	 * @return {number}
	 */
	var minArray = function(numbers) {
	    for(let i = numbers.length - 1; i > 0; i--) {
	        if(numbers[i - 1] > numbers[i]) {
	            return numbers[i]
	        }
	    }
	    return numbers[0]
	};

b、二分查找
这里要明确,因为原本是单调递增的数组,所以哪怕逆转了后,也是局部递增的,也就是说结果一般都出现在最小的那个二分数组的左边,所以我们比较right,也移动right,以免漏掉第一个

	/**
	 * @param {number[]} numbers
	 * @return {number}
	 */
	var minArray = function(numbers) {
	    let left = 0
	    let right = numbers.length - 1
	    // 要找某个值,二分查找就不需要等号
	    // 找某个范围,二分查找就需要等号
	    while(left < right) {
	        let middle = Math.floor((left + right) / 2)
	        // 这里其实没有拿left跟middle比较(因为要么即全拿left比较,要么全拿right比较)
	        if(numbers[right] > numbers[middle]) {
	            right = middle
	        } else if(numbers[right] < numbers[middle]) {
	            left = middle + 1
	        } else {
	            // 这里是重点,只能用right--,毕竟用的是right比较
	            right--
	        }
	    }
	    // 这里使用left或者right都行,毕竟此时left===right
	    return numbers[right]
	};

10、剑指 Offer 12. 矩阵中的路径
在这里插入图片描述

	/**
	 * @param {character[][]} board
	 * @param {string} word
	 * @return {boolean}
	 */
	var exist = function(board, word) {
	    // 表示现在从第几行,第几列,找第几个数
	    let dfs = function(row, col, num) {
	        // 如果要找的数找完了就返回true
	        if(num >= word.length) {
	            return true
	        }
	
	        // 如果下标越界,那也不是
	        if(row < 0 || row >= board.length || col < 0 || col >= board[0].length) {
	            return false
	        }
	
	        // 如果这个数不是或已经被访问过那就返回false
	        if(board[row][col] !== word[num] || board[row][col] === '') {
	            return false
	        }
	
	        // 把这个值标记成已被访问过
	        let temp = board[row][col]
	        board[row][col] = ''
	        // 这里有四种情况,上,下,左,右(任意一个成功即可)
	        let next = dfs(row - 1, col, num + 1) || dfs(row + 1, col, num + 1) || dfs(row, col - 1, num + 1) || dfs(row, col + 1, num + 1)
	        // 这里要还原(毕竟可能还需要再递归一次(当最开始传入的i和j不同时))
	        board[row][col] = temp
	        return next
	    }
	
	    for(let i = 0; i < board.length; i++) {
	        for(let j = 0; j < board[0].length; j++) {
	            if(dfs(i, j, 0)) {
	                return true
	            }
	        }
	    }
	    return false
	};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值