LeetCode刷题笔记

这篇博客记录了作者在LeetCode上的刷题体验,涵盖了买股票最佳时机、合并区间、链表操作、爬楼梯问题等经典算法题目,还讨论了排序算法如冒泡、插入和快速排序,以及背包问题和数组与二叉树之间的转换。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.买股票和卖股票最佳时机

/**
 * 给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。

你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。

返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0 
 * @param {number[]} prices
 * @return {number}
 */
var maxProfit = function(prices) {
    var max = 0
    var min =  prices[0]
    for(var i=1;i<prices.length;i++){
        var temp = prices[i] - min
        max = temp > max ? temp : max
        min = min>prices[i]?prices[i]:min
    }
    return max
};

2. 合并区间

/**
 * 以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi] 。请你合并所有重叠的区间,并返回 一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间 。
示例 1:
输入:intervals = [[1,3],[2,6],[8,10],[15,18]]
输出:[[1,6],[8,10],[15,18]]
解释:区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6].
示例 2:
输入:intervals = [[1,4],[4,5]]
输出:[[1,5]]
解释:区间 [1,4] 和 [4,5] 可被视为重叠区间。
 * @param {number[][]} intervals
 * @return {number[][]}
 */
var merge = function(intervals) {
    intervals = intervals.sort((a,b)=>a[0]-b[0])
    var result = [intervals[0]]
    for(var i = 1;i<intervals.length;i++){
        var last = result[result.length-1]
        var current = intervals[i]
        if(current[0] > last[1]){
            result.push(current)
        }else{
            result[result.length-1] = [last[0],Math.max(last[1],current[1])]
        }
    }
    return result
};

3.合并两个有序链表


/**
 * Definition for singly-linked list.
 * function ListNode(val, next) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.next = (next===undefined ? null : next)
 * }
 */
/**
 * @param {ListNode} l1
 * @param {ListNode} l2
 * @return {ListNode}
 */
var mergeTwoLists = function(l1, l2) {
    if (l1 === null) {
        return l2;
    } else if (l2 === null) {
        return l1;
    } else if (l1.val < l2.val) {
        l1.next = mergeTwoLists(l1.next, l2);
        return l1;
    } else {
        l2.next = mergeTwoLists(l1, l2.next);
        return l2;
    }
};

4. 爬楼梯

var climbStairs = function(n) {
    // 定义一个数组来保存每一层楼梯的不同爬法数
    const dp = new Array(n + 1);
    // 初始状态:第0层和第1层的不同爬法数均为1
    dp[0] = 1;
    dp[1] = 1;
    // 状态转移方程:第i层的不同爬法数等于第i-1层和第i-2层的不同爬法数之和
    for (let i = 2; i <= n; i++) {
      dp[i] = dp[i - 1] + dp[i - 2];
    }
    // 最终结果为第n层的不同爬法数
    return dp[n];
  };

假设有0级台阶、1阶台阶、2阶台阶。。。n级台阶,所以设置一个长度为(n+1)的数组。如果最终爬到了n级台阶,那么在这之前的一步,根据题意,
一定是爬了1或2个台阶才上到了n级台阶的,所以爬到n级台阶的爬法数是爬到(n-1)级台阶爬法数和爬到(n-2)级台阶爬法数的和,这就有点像斐波那契数列的公式一样。

  • 使用最小花费爬楼梯
var minCostClimbingStairs = function(cost) {
    const n = cost.length;
    // 定义一个数组来保存到达每个台阶的最小花费
    const dp = new Array(n);
    // 初始状态:到达第0个和第1个台阶的最小花费均为对应的费用
    dp[0] = cost[0];
    dp[1] = cost[1];
    // 状态转移方程:第i个台阶的最小花费为从第i-1个台阶和第i-2个台阶中选择最小花费加上到达第i个台阶的费用
    for (let i = 2; i < n; i++) {
      dp[i] = Math.min(dp[i - 1], dp[i - 2]) + cost[i];
    }
    // 比较从第n-1个台阶上楼顶和从第n-2个台阶上楼顶的花费,选较小的那个
    return Math.min(dp[n - 1], dp[n - 2]);
  };

5.01背包算法

/**
* @description
* 01背包算法
* @private
* @param {any} dataList 红包列表 
* @param {any} all 下单金额
* @returns 
*/
function knapsack(dataList, all) {
    const returnList = [];
    for (let i = 0; i < dataList.length; i++) {
        // 构建二维数组
        returnList[i] = [];
        for (let j = 0; j < all; j++) { // 分割背包
            const currentBagWeight = j + 1; // 此时背包重量
            const currentWeight = dataList[i].rangeBegin; // 此时物品重量
            const currentValue = dataList[i].amount; // 此时的价值
            const lastW = currentBagWeight - currentWeight; // 此时背包重量减去此时要添加的物品后的重量

            // 求子问题最优解,并记录
            let fV = lastW >= 0 ? currentValue : 0;
            fV = fV + (i > 0 && returnList[i - 1][lastW - 1] ? returnList[i - 1][lastW - 1] : 0);
            const nV = i > 0 && returnList[i - 1][j] ? returnList[i - 1][j] : 0;
            returnList[i][j] = Math.max(fV, nV);
        }
    }

    // 回溯算法,算出选择的商品
    let y = all - 1;
    const selectItem = [];
    let i = dataList.length - 1;

    while (i > -1) {
        if (returnList[i][y] === (returnList[i - 1] && returnList[i - 1][y - dataList[i].rangeBegin] || 0) + dataList[i].amount) {
            selectItem.push(dataList[i]);
            y -= dataList[i].rangeBegin;
        }
        i--;
    }

    return selectItem;
}

6. 三数之和

/**给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != j、i != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请

你返回所有和为 0 且不重复的三元组。

注意:答案中不可以包含重复的三元组。
 * @param {number[]} nums
 * @return {number[][]}
 */
var threeSum = function(nums) {
    const length = nums.length
    var result = []
    if(length===3){
        var sum = nums.reduce((l,r)=>l+r)
        result = sum === 0 ? [nums]: []
    }else{
        let array = []
        nums = nums.sort((a,b)=>a-b)
        for(var i =0 ;i<length;i++){
            for(var j=i+1;j<length;j++){
                for(var k=i+2;k<length;k++){
                    const threeArr = [nums[i],nums[j],nums[k]]
                    const sort = threeArr.sort().toString()
                    if(!array.includes(sort)){
                        array.push(sort) 
                        if((threeArr[0]+threeArr[1]+threeArr[2]) === 0 && i!=j&& j!=k && i!=k){
                            result.push(threeArr)
                        }
                    }
                }
            }
        }
    }
    return result
};
console.log(threeSum([-2,0,1,1,2]))

7. 字母异位词分组

/**给你一个字符串数组,请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。
字母异位词 是由重新排列源单词的所有字母得到的一个新单词。
示例 1:
输入: strs = ["eat", "tea", "tan", "ate", "nat", "bat"]
输出: [["bat"],["nat","tan"],["ate","eat","tea"]]
示例 2:
输入: strs = [""]
输出: [[""]]
示例 3:
输入: strs = ["a"]
输出: [["a"]]
 * @param {string[]} strs
 * @return {string[][]}
 */
var groupAnagrams = function(strs) {
    if(strs.length === 1){
        return [strs]
    }else{
        var map = {}
        for(var i= 0 ; i<strs.length; i++){
            var array = Array.from(strs[i]).sort()
            var key = array.toString()
           if(map.hasOwnProperty(key)){
               var temp = map[key]
               temp.push(strs[i])
               map[key] = temp
           }else{
               map[key] = [strs[i]]
           }
        }
        return Object.values(map)
    }
};

8.最小覆盖子串

/**
 * @param {string} s
 * @param {string} t
 * @return {string}
 */
var minWindow = function(s, t) {
  let l = 0;
let r = 0;
const need = new Map();
for(let c of t){
    need.set(c, need.has(c) ? need.get(c) + 1 : 1);
}
let needType = need.size;
let res = '';
while(r < s.length){
    const c = s[r];
    if(need.has(c)){
        need.set(c, need.get(c) - 1);
        if(need.get(c) === 0) needType -= 1;
    }
    while(needType === 0){
        const newRes = s.substring(l, r + 1);
        if(!res || newRes.length <res.length) res = newRes;
        const c2 = s[l];
        if(need.has(c2)){
            need.set(c2, need.get(c2) + 1);
            if(need.get(c2) === 1) needType += 1;
        }
        l += 1;
    }
    r += 1;
}
return res;
}

9. 给定数组转换成二叉树


/**
 * 给定数组转换成二叉树
 * @param {} val_list 
 */
function buildTree(val_list){
    //数组为空
    if(!val_list || val_list.length === 0){
        return
    }
    //根结点
    var root = new TreeNode(val_list.shift());
    var nodeQueue = [root];

    //对根节点进行操作,更新node
    while(val_list.length>0){
        var node = nodeQueue.shift();
        //构建左孩子节点
        var leftVal = val_list.shift();
        if(val_list.length === 0) break
        if(leftVal){
            node.left = new TreeNode(leftVal);
            nodeQueue.push(node.left);
        }
        //构建右孩子节点
        var rightVal = val_list.shift();
        if(val_list.length === 0) break;
        if(rightVal){
            node.right = new TreeNode(rightVal);
            nodeQueue.push(node.rightVal)
        }
    }
    return root
}

function TreeNode(val,left,right){
    this.val = val === undefined ?  0 : val;
    this.left = left === undefined ? null : left;
    this.right = right === undefined ? null : right;
}

var root = [3,9,20,null,null,15,7];

let tree = buildTree(root)
console.log(tree);

10.数组转换成数,树转换成数组,转来转去的,去实现一下

//为啥要这么做呢,因为arrayList这种格式一般是数据库存储的格式,而treeList一般是前端menu的展示数据格式,所以这个算法场景很常见
const arrayList =  [
    {id: 1, name: '部门1', pid: 0},
    {id: 2, name: '部门2', pid: 1},
    {id: 3, name: '部门3', pid: 1},
    {id: 4, name: '部门4', pid: 3},
    {id: 5, name: '部门5', pid: 4},
]
const treeList = [
    {
        "id": 1,
        "name": "部门1",
        "pid": 0,
        "children": [
            {
                "id": 2,
                "name": "部门2",
                "pid": 1,
                "children": []
            },
            {
                "id": 3,
                "name": "部门3",
                "pid": 1,
                "children": [
                    // 结果 ,,,
                ]
            }
        ]
    }
]
function arrayToTree(array){
    //递归查找获取子节点
    let tree = []
    const getChildren = (array,pid)=>{
        const children = []
        array.forEach(item => {
            if(item.id === pid){
                children.push(item)
            }
        })
    }
    getChildren(array,pid)
    return tree
}

function treeToArray(tree){
    let array = []
    return array
}
console.log(treeToArray())

11.冒泡排序

const arr = [5, 2, 7, 8, 34, 7, 39, 12, 56, 9, 1]

  function bubbleSort(arr) {
    const len = arr.length
    // 外层循环i控制比较的轮数
    for (let i = 0; i < len; i++) {
      // 里层循环控制每一轮比较的次数j,arr[i] 只用跟其余的len - i个元素比较
      for (let j = 1; j < len - i; j++) {
        // 若前一个元素"大于"后一个元素,则两者交换位置
        if (arr[j - 1] > arr[j]) {
          [arr[j - 1], arr[j]] = [arr[j], arr[j - 1]]
        }
      }
    }
    return arr
  }

  console.log(bubbleSort(arr))	// [1, 2,  5,  7,  7, 8, 9, 12, 34, 39, 56]
 

12.插入排序

const arr = [5, 2, 7, 8, 34, 7, 39, 12, 56, 9, 1]

function insertSort(arr) {
  const handle = [arr[0]], len = arr.length
  for (let i = 1; i <= len - 1; i++) {
    const current = arr[i]
    for (var j = handle.length - 1; j >= 0; j--) {
      if (current > handle[j]) {
        handle.splice(j + 1, 0, current)
        break
      }
      if (j === 0) {
        handle.unshift(current)
      }
    }
  }
  return handle
}

console.log(insertSort(arr))	// [1, 2,  5,  7,  7, 8, 9, 12, 34, 39, 56]

13.快速排序

const arr = [5, 2, 7, 8, 34, 7, 39, 12, 56, 9, 1]

function quickSort(arr) {
  // 4.结束递归(当ary小于等于一项,则不用处理)
  if (arr.length <= 1) {
    return arr
  }
  // 1. 找到数组的中间项,在原有的数组中把它移除
  const middleIndex = Math.floor(arr.length / 2)
  const middle = arr.splice(middleIndex, 1)[0]
  // 2. 准备左右两个数组,循环剩下数组中的每一项,比当前项小的放到左边数组中,反之放到右边数组中
  const leftArr = [], rightArr = []
  for (let i = 0; i < arr.length; i++) {
    const current = arr[i]
    current < middle ? leftArr.push(current) : rightArr.push(current)

  }
  // 3. 递归方式让左右两边的数组持续这样处理,一直到左右两边都排好序为止。
  //(最后让左边+中间+右边拼接成最后的结果)
  return quickSort(leftArr).concat(middle, quickSort(rightArr))
}

console.log(bubbleSort(arr))	// [1, 2,  5,  7,  7, 8, 9, 12, 34, 39, 56]

14. 01背包问题

// 题目描述:
// 有 n 个物品和一个大小为 m 的背包. 给定数组 A 表示每个物品的大小和数组 V 表示每个物品的价值.
// 问最多能装入背包的总价值是多大?
// 示例1:
// 输入: m = 10, A = [2, 3, 5, 7], V = [1, 5, 2, 4]
// 输出: 9
// 解释: 装入 A[1] 和 A[3] 可以得到最大价值, V[1] + V[3] = 9
// 示例2:
// 输入: m = 10, A = [2, 3, 8], V = [2, 5, 8]
// 输出: 10
// 解释: 装入 A[0] 和 A[2] 可以得到最大价值, V[0] + V[2] = 10

function knapSack(w,val,capacity,n){
	var T = []

	for(let i = 0;i < n;i++){
		T[i] = [];
		for(let j=0;j <= capacity;j++){
			if(j === 0){ //容量为0
				T[i][j] = 0;
				continue;
			}	
			if(j < w[i]){ //容量小于物品重量,本行hold不住
				if(i === 0){
					T[i][j] = 0; // i = 0时,不存在i-1,所以T[i][j]取0

				}else{
					T[i][j] = T[i-1][j]; //容量小于物品重量,参照上一行

				}
				continue;
			}
			if(i === 0){
				T[i][j] = val[i]; //第0行,不存在 i-1, 最多只能放这一行的那一个物品
			}else{
				T[i][j] = Math.max(val[i] + T[i-1][j-w[i]],T[i-1][j]);

			}
		}

	}

	findValue(w,val,capacity,n,T);


	return T;
}
//找到需要的物品
function findValue(w,val,capacity,n,T){

	var i = n-1, j = capacity;
	while ( i > 0 && j > 0 ){

		if(T[i][j] != T[i-1][j]){
			console.log('选择物品'+i+',重量:'+ w[i] +',价值:' + values[i]);
			j = j- w[i];
			i--;
		}else{
			i--;  //如果相等,那么就到 i-1 行
		}
	}
	if(i == 0 ){
		if(T[i][j] != 0){ //那么第一行的物品也可以取
			console.log('选择物品'+i+',重量:'+ w[i] +',价值:' + values[i]);

		}
	}
}

// w = [2,3,4].  val = [3,4,5] , n = 3 , capacity = 5
//function knapSack([2,3,4],[3,4,5],5,3);
// 
var values = [3,4,5],
	weights = [2,3,4],
	capacity = 5,
	n = values.length;

console.log(knapSack(weights,values,capacity,n));
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

为了WLB努力

给点小钱,你的鼓励是我坚持动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值