leetcode前端JS算法入门(持续更新)

一、数组

  1. 给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。【二分查找】
// 方法一:
var search = function(nums, target) {
   let left = 0;
   let right = nums.length - 1;
   let mid;
   while(left <= right) {
       mid = left + (right - left) - 1;  
       if (nums[mid] > target) {  // 大于目标值
           right = mid - 1;
       } else if (nums[mid] < target) {  // 小于目标值
           left = mid + 1;
       } else {
           return mid;
       }
   }
   return -1;
};
// 总结: 会超时中间的代码还需要进行优化

// 方法二:
var search = function(nums, target) {
   let left = 0, right = nums.length - 1, mid;
   while(left < right) {  // 条件结束的时候left = right,不需要判断是否相等
       mid = left + Math.floor((right - left) / 2); 
       if (nums[mid] > target) {
           right = mid - 1;
       } else if (nums[mid] < target) {
           left = mid + 1;
       } else {
           return mid;
       }
   }
   return nums[left] == target ? left : -1;  // 第一次取mid值之后,下一次都是判断nums[left]是否和target相等,可以自己手写验证下,所以这里是判断nums[left]的值
};
  1. 给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。

例如:
输入: num = [2, 3, 2, 4, 2], val = 2;
输出: 2, [3, 4] 是留下来的元素

< !-- 
	 解题思路:
	 1. 使用双层for循环的暴力解法
	 2. 使用数组的splice方法
	 3. 使用双指针方法
-->
// 方法一:暴力解法
var removeElement = function(nums, val) {
    //  定义i,j,两个for循环判断是否相等
   let i,j;
    for (i = 0; i < nums.length; i++) {
        if (nums[i] == val) {
            for (j = i + 1; j < nums.length; j++) {
                nums[j - 1] = nums[j];
            }
            i--;
            nums.length--;
        }
    }
    return nums.length;
};

// 方法二:使用数组的splice方法
var removeElement = function(nums, val) {
for (let i = 0; i < nums.length; i++) {
        if (nums[i] == val) {
            nums.splice(i, 1);  // 移除当前的重复值
            i--;
        }
    }
    return nums.length;
}

// 方法三:使用双指针法,
var removeElement = function(nums, val){
	const len = nums.length;
	let left = 0, right;
	for (right = 0; right < len; right++) {
		if (nums[right] !== val) {
			nums[left] = nums[right];  // 判断快指针的值是否是val,不是的话就将right指向的元素赋值给left进行覆盖
			left++;
		}
	}
	return left;  // left的长度就是最终的新数组长度
}
  1. 给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。

例如:
输入: nums = [1,3,5,6], target = 5
输出: 2

// 第一种方法: 二分查找法
var searchInsert = function(nums, target) {
    	// 首先判断两个端点的值是否包含target
    if (nums[0] > target) {
        return 0;
    } else if (nums[nums.length - 1] < target) {
        return nums.length;  // 这里不需要返回Nums.length - 1;
    }
    let len = nums.length - 1;
    let left = 0;
    while (left <= len) {
        let mid = Math.round((left + len) / 2);
        if (nums[mid] > target) {
            left = mid - 1;
        } else if (nums[mid] < target) {
            left = mid + 1;
        } else {
            return mid;
        }
    }
    return left;
};

// 第二种方法:直接遍历整个数组看是否有和target相等的元素,如果有就返回当前元素的索引值
var searchInsert = function(nums, target) {
	for (let i = 0; i < nums.length; i++) {
		if (nums[i] == target) return i;
	}
	return nums.length;
}
  1. 给定一个由 整数 组成的 非空 数组所表示的非负整数,在该数的基础上加一。最高位数字存放在数组的首位, 数组中每个元素只存储单个数字。你可以假设除了整数 0 之外,这个整数不会以零开头。

例如:
输入[1, 3, 4, 8] 或者 [1, 2, 9]
输出: [1, 3, 4, 9] 或者 [1, 3, 0]

// 方法一: 使用for循环倒着遍历,然后当前元素和10取模判断是否存在,存在就返回数组
var plusOne = function(digits) {
	for (let i = digits.length - 1; i >=0; i--) {
		digits[i]++;
		digits[i] = digits % 10;
		if (digits[i]) return digits;
	}
	// 这里适用于特殊情况 [9] 
	digits.unshift(1);
	return digits;
}

// 方法二:循环遍历判断是否当前元素值小于9
	// < 9  当前元素就自增,同时返回数组
	// > 9  当前元素的值就为0,返回[1, ...digits]
var plusOne = function(digits) {
	for (let i = digits.length - 1; i >= 0; i--) {
		if (digits[i] < 9) {
			digits[i]++;
			return digits;
		}
		// 不小于9,说明可能刚好这个元素就是9,让它的值为0
		digits[i] = 0;
	}
	return [1, ...digits];
}
  1. 给定两个数组,arr1 和 arr2,其中arr1里面的元素都存在于arr2里面,但是arr1里面还有没存在于arr2里面的元素;将重复的元素输出,同时将不存在与arr2里面的元素进行升序之后再输出

例如:
输入:arr1 = [2,3,1,3,2,4,6,7,9,2,19], arr2 = [2,1,4,3,9,6]
输出:[2,2,2,1,4,3,3,9,6,7,19]

// 方法一:  遍历 + 过滤 + 排序
var relativeSortArray = function(arr1, arr2) {
	let newArr = [];
	// 1. 遍历找出arr1里面和arr2相同的元素,如果存在就push到新数组里面存储,包含重复的元素
	for (var i = 0; i < arr2.length; i++) {  // 外层循环必须是arr2
		for (var j = 0; j < arr1.length; j++) {
			if (arr2[i] == arr1[j]) {
				newArr.push(arr1[j])
			}
		}
	}
	// 2.将arr1数组进行过滤(留下新数组里面不存在的值),然后将过滤出来的值进行排序添加到新数组当中
	newArr.push(...arr1.filter(item => newArr.indexOf(item) == -1).sort(a, b) => a -b));
	return newArr;
}
  1. 给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0 。

例如:
输入:[7,1,5,3,6,4]
输出: 5
解析: 在第二天的时候买入(i = 1) 在第五天的时候卖出(i = 6) 这样才能获取到最大利润5

// 方法一: 使用Math.max / min 方法来进行计算最大利润
var maxProfit = function(prices) {
	if (prices.length < 2) return 0;
	let res = 0, minPrices = prices[0];  // 假设第一个值就为最小值
	for (var i = 1; i < prices.length; i++) {
		res = Math.max(res, prices[i] - minPrices);  // 取出后一个元素减去前一个元素的最大值
		minPrices = Math.min(minPrices, prices[i]);  // 取出当前元素和minprices对比的最小值
	}
	return res;
}

// 方法二:定义一个最小值,遍历是否元素i小于这个最小值,如果不小于就取出大的值就是最大利润
var maxProfit = function(prices) {
	let min = Number.MAX_SAFE_INTEGER;  // MAX_SAFE_INTEGER是JavaScript中的一个常量,它表示JavaScript中可以安全表示的最大整数。 (不去深究,定义就行)
	let max = 0;
	for (var i = 0; i < prices.length; i++) {
		if (prices[i] < min) {
			min = prices[i];
		} else {
			max = Math.max(max, prices[i] - min);
		}
	}
	return max;
}
  1. 给定一个大小为 n 的数组 nums ,返回其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。你可以假设数组是非空的,并且给定的数组总是存在多数元素。

例如:
输入: [1, 2, 3, 3, 3, 3, 2]
输出: [3]

// 方法一:排序
var majorityElement = function(nums) {
	nums.sort((a, b) => a - b);
	return nums[Math.floor(nums.length / 2)];  // 排序之后返回数组的中间那个数一定就是出现次数最多的那个元素
}

// 方法二:搞个对象
var majorityElement = function(nums) { 
	let half = nums.length / 2;
	let obj = {};
	for (const num of nums) {
		obj[num] = (obj[num] || 0) + 1;  // 将遍历的所有元素存储到对象里面 键:该元素  值:出现的次数
		if (obj[num] > half) return num;		// 如果该元素的次数大于half就返回
	}
}

二、链表

  1. 将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。

例如:
输入: list1 = [1, 2, 4, 9] list2 = [2, 4, 4, 5];
输出: list_result = [1, 2, 2, 4, 4, 4, 5, 9];

// 方法一: 使用递归的方法
var mergeTwoLists = function(list1, list2) {
	if (list1 == null) return list2;
	if (list2 == null) return list1;
	if (list1.val > list2.val) {  // 这里不能写list1.value  链表
		list2.next = mergeTwoLists(list2.next, list1);
		return list2;
	} else {
		list1.next = mergeTwoLists(list1.next, list2);
		return list1;
	}
}

递归注意点:

  1. 该问题的子问题是什么?
  2. 当前层需要做什么? 一定不要去想下一层,下下层…
  3. 递归结束的条件?

以上题目都来自于leetcode,如果需要更加详细的算法学习可以上https://leetcode.cn,谢谢!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值