小浩算法 javascript解题一(数组篇)

    科技2024-08-04  26

    数组篇


    前言

    国庆长假没有出去给社会添堵,在家就找点事情来做,恰好最近对算法需要进行系统的补足。网上leetcode刷题圈内比较火,但又找不到刷题的方向,本着做题比选题简单的原则就在github上找到了小浩算法,来参考学习下。


    两个数组的交集

    给定两个任意长度的数组,编写一个函数来计算它们的交集。

    // 例子1 const arr1 = [22, 3, 89, 36, 0, 42, 12, 51] const arr2 = [12, 0, 100, 10, 5, 36] // 输出结果 [12, 0, 36] // 例子2 const arr1 = [8, 2, 1, 5, 7, 9] const arr2 = [100, 3, 101] // 输出结果 []

    以下为解题代码:

    const intersect = (arr1 = [], arr2 = []) => { // 声明一个结果数组 const result = [] // 利用Set对象,将第一个数组生成一个查询集合 // 需要注意Set对象会自动去重,如果不希望发生,可以用Map或者Object代替 const arrSet = new Set(arr1) for (let i = 0; i < arr2.length; i ++) { // 遍历第二个数组的每个元素与之前的Set集合进行查询,如果成功则将当前元素放入结果数组 if (arrSet.has(arr2[i])) result.push(arr2[i]) } return result }

    题目进阶:

    题目在进阶问题中问道:如果给定的数组已经排好序呢?你将如何优化你的算法? 假如两个数组都是有序的,分别为:arr1 = [1,2,3,4,4,13],arr2 = [1,2,3,9,10]

    以下为解题代码:

    const intersect2 = (arr1 = [], arr2 = []) => { const result = [] // arr1的起始下标 let i1 = 0 // arr2的起始下标 let i2 = 0 // 其中一个数组的下标越界就结束循环 while (i1 < arr1.length && i2 < arr2.length) { if (arr1[i1] < arr2[i2]) i1 += 1 else if (arr1[i1] > arr2[i2]) i2 += 1 else { result.push(arr1[i1]) i1 += 1 i2 += 1 } } return result }

    最长公共前缀

    编写一个函数来查找字符串数组中的最长公共前缀。如果不存在公共前缀,则返回""

    // 例子1 const arr = ['funtion', 'funk', 'ful'] // 输出结果 'fu' // 例子1 const arr = ['abc', 'ijk', 'xyz'] // 输出结果 ''

    以下为解题代码:

    const maxPrefix = (arr = []) => { // 初始化结果 let result = arr[0] || '' // 递归获取前缀 const getPrefix = (str = '', prefix = '') => { if (str.indexOf(prefix) > -1) return prefix // 如果当前字符串的长度短于进行比较的前缀,两者互换以减少递归次数 if (str.length < prefix.length) { const temp = prefix prefix = str str = temp } // 去掉前缀最后一位 prefix = prefix.slice(0, prefix.length - 1) return getPrefix(str, prefix) } for (let i = 0; i < arr.length; i ++) { result = getPrefix(arr[i], result) // 递归计算后出现前缀无解,就立即结束循环 if (result.length < 1) break } return result }

    买卖股票的最佳时机 II

    给定一个数组来表示一支股票,它的第 i个元素是第 i 天的价格。 如果你同时最多只允许完成一笔交易(即买入和卖出一支股票),设计一个算法来计算你所能获取的最大利润。注意你不能在买入股票前卖出股票。

    // 例子1 const arr = [5, 2, 5, 10, 6, 9] // 2买入10卖出,6买入9卖出 // 输出结果11 // 例子1 const arr = [10, 6, 4, 3, 1] // 输出结果 0

    以下为解题代码:

    const stockTrading = (data = []) => { // 初始化结果 let result = 0 // 初始化买入价 let buyPrice = data[0] for (let i = 0; i < data.length; i ++) { // 卖出逻辑 if (data[i - 1] > data[i]) { // 结算收益 result += data[i - 1] - buyPrice // 重新买入 buyPrice = data[i] continue } // 最后一个交易日,单独结算 if (i >= data.length - 1) result += data[i] - buyPrice } return result }

    旋转数组

    给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数。

    // 例子 const nums = [1, 2, 3, 4, 5, 6, 7] const k = 3 // 输出结果 [5, 6, 7, 1, 2, 3, 4]

    说明: 尽可能想出更多的解决方案,至少有三种不同的方法可以解决这个问题。 要求使用空间复杂度为 O(1) 的 原地 算法。

    以下为解题代码:

    // 方法1 const rotate1 = (arr = [], k = 3) => { k = k % arr.length arr.splice(0, 0, ...arr.splice(arr.length - k)) return arr } // 方法2 const rotate2 = (arr = [], k = 3) => { k = k % arr.length const recursion = (arr, k) => { if (k < 1) return arr arr.unshift(arr.pop()) return rotate2(arr, k -= 1) } return recursion(arr, k) } // 方法3 与第一种方法类似 const rotate3 = (arr = [], k = 3) => { k = k % arr.length return arr.splice(arr.length - k).concat(arr) }

    原地删除

    给定一个数组 nums 和一个值 val,你需要原地移除所有数值等于 val 的元素,返回移除后数组的新长度。 不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。

    // 例子 const nums = [1, 1, 2, 2, 3, 3] const val = 2 // 输出结果 [1, 1, 3, 3]

    以下为解题代码:

    const deleteValue = (nums = [], val = 0) => { for (let i = 0; i < nums.length;) { if (nums[i] === val) { nums.splice(i, 1) continue } i ++ } return [nums, nums.length] }

    扩展题型:

    给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次。 返回移除后数组的新长度。不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。

    // 例子 const nums = [1, 1, 2, 2, 3, 4, 4] // 输出结果 [1, 2, 3, 4]

    以下为解题代码:

    const deleteRepeat = (nums = []) => { for (let i = 0; i < nums.length;) { if (nums[i] === nums[i + 1]) { nums.splice(i, 1) continue } i ++ } return [nums, nums.length] }

    加一

    给定一个由整数组成的非空数组所表示的非负整数,在该数的基础上加一。 最高位数字存放在数组的首位, 数组中每个元素只存储单个数字。你可以假设除了整数 0 之外,这个整数不会以零开头。

    // 例子1 const nums = [1, 2, 3] // 输出结果 [1, 2, 4] // 例子2 const nums = [9, 9] // 输出结果 [1, 0, 0]

    以下为解题代码(扩展成加任意非负整数):

    const add = (nums = [], num = 1) => { if (nums.length < 1) nums.push(0) const len = nums.length const recursion = (a, n) => { if (n < 10) { a.unshift(n) return a } a.unshift(n % 10) return recursion(a, n / 10 << 0) } num = Math.abs(num << 0) for (let i = len - 1; i >= 0; i --) { if (i === len - 1) { nums[i] += num } if (nums[i] >= 10) { const tempNum = nums[i] / 10 << 0 nums[i] %= 10 if (i - 1 < 0) recursion(nums, tempNum) else nums[i - 1] += tempNum } } return nums }

    两数之和

    给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。 你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。

    // 例子 const nums = [2, 7, 11, 15], target = 9 // 输出结果 [0, 1]

    以下为解题代码:

    const towSum = (nums = [], target = 0) => { // 初始化结果 const result = [] // 创建Map集合 const map = new Map(nums.map((v, i) => [v, i])) for (let i = 0; i < nums.length; i ++) { const value = target - nums[i] // 不能数不能是同一个值 if (map.has(value) && map.get(value) !== i) { result.push.apply(result, [i, map.get(value)]) break } } return result }

    三数之和

    给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有满足条件且不重复的三元组。注意:答案中不可以包含重复的三元组。

    // 例子 const nums = [-1, 0, 1, 2, -1, -4] // 满足要求的三元组集合为: [ [-1, 0, 1], [-1, -1, 2] ]

    以下为解题代码:

    const threeSum = (nums = []) => { // 初始化结果 const result = [] const len = nums.length // 升序排序 nums = nums.sort((a, b) => a - b) for (let i = 0; i < len; i ++) { const seed = nums[i] let l = i + 1 let r = len - 1 if (nums[i] >= 0) break while (l !== r) { if (seed + nums[l] + nums[r] < 0) l += 1 else if (seed + nums[l] + nums[r] > 0) r -= 1 else { result.push([seed, nums[l], nums[r]]) break } } } return result }

    Z字形变换

    将一个给定字符串根据给定的行数,以从上往下、从左到右进行 Z 字形排列。

    const str = 'LEETCODEISHIRING', numRows = 4 // 输出结果 'LDREOEIIECIHNTSG' // 介个样子: L D R E O E I I E C I H N T S G

    以下为解题代码:

    const ZTransform = (strings = '', rowNum = 4) => { const result = [] const len = strings.length let dir = 1 let seed = 0 for (let i = 0; i < len; i ++) { result[seed] = (result[seed] || '') + strings[i] if (seed === 0) dir = 1 else if (seed === rowNum - 1) dir = -1 seed += dir } return result.join('') }

    提示:

    很多时候,读题、审题要比解题更重要


    后记

    虽然做开发很多年了,但由于是半路出家,基本上工作,就埋头在业务层面,忽略了最基本的东西。 计划后续会陆续将小浩算法里面所有的题都用javascript过一遍。

    最后支持下小浩算法

    Processed: 0.010, SQL: 8