js算法基础-01

news2025/4/8 10:30:08

文章目录

  • 1、双指针
  • 2、快慢指针
  • 3、滑动指针
  • 4、哈希表
  • 5、汇总区间
  • 6、栈
  • 7、进制求和
  • 8、数学
  • 9、动态规划

js算法基础, 每个重要逻辑思路,做一下列举

1、双指针

  • 有序数组合并:一般思路就是合并、排序,当然效率略低
  • 题目1:nums1中取前m个元素,nums2中取前n个元素,组成新的有序数组,最后结果写入nums1
  • 思路:双指针,两个数组各自一个指针,该位置就是未参与排序的最小值
// 一般思路
const merge = function (nums1, m, nums2, n) {
  const mergedArray = [...nums1.slice(0, m), ...nums2.slice(0, n)]; // 合并
  mergedArray.sort((a, b) => a - b); // 修改原数组,重新排序
  // 数组内容粘贴,一般出现在修改原数组的时候
  for (let i = 0; i < merged.length; i++) {
    nums1[i] = merged[i];
  }
  return nums1;
};

console.log(merge([1, 2, 3, 0, 0, 0], 3, [2, 5, 6], 3));
// 双指针
const merge = function (nums1, m, nums2, n) {
  const target1 = nums1.slice(0, m); // 截取后目标数组
  const target2 = nums2.slice(0, n);
  let index1 = 0; // 每个数组一个排序位置的指针
  let index2 = 0;
  for (let i = 0; i < m + n; i++) {
    const num_1 = target1[index1]; // 每个数组取出的元素
    const num_2 = target2[index2];
    // 边界条件
    if (index1 >= m) {
      // 这里表示数组1已经取完了,那么剩下的全部取数组2的元素即可
      nums1[i] = num_2;
      index2++;
    } else if (index2 >= n) {
      nums1[i] = num_1;
      index1++;
    } else if (num_1 < num_2) {
      // 取最小值
      nums1[i] = num_1;
      index1++;
    } else {
      nums1[i] = num_2;
      index2++;
    }
  }
  return nums1;
};
console.log(merge([1, 2, 3, 0, 0, 0], 3, [2, 5, 6], 3));
  • 题目2:验证回文,返回是或者否
  • 思路1:当需要得到是否的时候,可以正向思考,所有满足即为true,也常见于反向思考,找出一个不符合的即为false,一般看条件苛刻程度,比如预测大部分都符合条件,那么就找出不符合的
  • 思路2:for循环里自变量i就是单指针
// 快速
var isPalindrome = function (s) {
  const str = s.toLowerCase().replace(/[^a-z0-9]/g, "");
  const strR = str.split("").reverse().join("");
  return str === strR;
};

// 双指针
var isPalindrome = function (s) {
  const str = s.toLowerCase().replace(/[^a-z0-9]/g, "");
  for (let i = 0, j = str.length - 1; i < j; i++, j--) {
    if (str[i] !== str[j]) return false;
  }
  return true;
};

// for循环,单指针
var isPalindrome = function (s) {
  const str = s.toLowerCase().replace(/[^a-z0-9]/g, "");
  for (let i = 0; i < str.length / 2; i++) {
    if (str[i] !== str[str.length - 1 - i]) {
      return false;
    }
  }
  return true;
};
console.log(isPalindrome("A man, a plan, a canal: Panama")); // true

2、快慢指针

  • 快慢指针:一般会出现在一个数组、一个目标数据中
  • 题目:删除有序数组中的重复项
  • 思路:由于有序数组中会出现重复的元素,所以慢指针指示写入的位置,快指针跳过重复的元素,直到下一个不同元素出现
var removeDuplicatesArray = [1, 1, 2];
var removeDuplicates = function (nums) {
  let slow = 0,
    fast = 1;
  while (fast < nums.length) {
    if (nums[slow] !== nums[fast]) {
      slow++;
      nums[slow] = nums[fast];
    }
    fast++;
  }
  return slow + 1;
};
console.log(removeDuplicates([1, 1, 2]), removeDuplicatesArray);

补充while 和 for的差异;可以看到差异很小,while没有初始化变量的位置,没有自增位置,只有终止逻辑;一般来说for更全面,while循环都可以改造成for循环;while适用于略微简化逻辑;

var removeDuplicates2 = function (nums) {
  let slow = 0,
    fast = 1;
  for (fast = 1; fast < nums.length; fast++) {
    if (nums[slow] !== nums[fast]) {
      slow++;
      nums[slow] = nums[fast];
    }
  }
  return slow + 1;
};

3、滑动指针

  • 滑动指针:需要对两个指针之间的元素进行计算,比如求和
  • 题目1:找出该数组nums中满足其总和大于等于 target 的长度最小的子数组,返回长度,
var minSubArrayLen = function (target, nums) {
  let length = nums.length,
    // 左指针缩小范围
    left = 0,
    // 右指针扩大范围
    right = 0,
    // sum 是动态和,有时比 target 小,有时比 target 大
    sum = 0,
    // 加1是为了断定是不是所有的元素都加起来都不够target
    minLen = length + 1;
  for (right = 0; right < length; right++) {
    sum += nums[right];
    // 只要sum大于等于target,一直移动左指针,并得到sum和
    while (sum >= target) {
      minLen = Math.min(minLen, right - left + 1); // 计算当前窗口的长度
      sum -= nums[left]; // 减去左指针的值
      left++; // 左指针右移
    }
  }
  return minLen === length + 1 ? 0 : minLen;
};
console.log(minSubArrayLen(5, [1, 4, 4])); // 2

4、哈希表

  • 哈希表:可以统计字符和存储数据
  • 题目1:判断 ransomNote 能不能由 magazine 里面的字符构成;每个字符只能使用一次;
var canConstruct = function (ransomNote, magazine) {
  // 对字符的个数进行统计
  const magazineObj = {};
  // 统计
  for (let i = 0; i < magazine.length; i++) {
    const char = magazine[i];
    if (magazineObj[char]) {
      magazineObj[char]++;
    } else {
      magazineObj[char] = 1;
    }
  }
  // 检验
  for (let i = 0; i < ransomNote.length; i++) {
    const char = ransomNote[i];
    // 减到0就说明没了,返回false
    if (magazineObj[char]) {
      magazineObj[char]--;
    } else {
      return false;
    }
  }
  return true;
};
console.log(canConstruct("aa", "ab")); // false
  • 题目2:两数之和,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标;这里规定只有一对满足条件
  • 思路:两个值,刚好可以用哈希key:value完成记录;(还有三数之和等)
var twoSum = function (nums, target) {
  const numsObj = {};
  // 统计
  for (let i = 0; i < nums.length; i++) {
    const item = nums[i];
    // 注意 索引0是存在配对数的,要判断undefined才准确
    if (numsObj[item] !== undefined) {
      return [numsObj[item], i];
    } else {
      numsObj[target - item] = i; // 记录配对数 对应的索引
    }
  }
  return [];
};

console.log(twoSum([2, 7, 11, 15], 9)); // [0, 1]

5、汇总区间

汇总区间

  • 题目1:给定一个 无重复元素 的 有序 整数数组 nums,返回区间汇总
var summaryRanges = function (nums) {
  // 区间起点指针
  let index = 0,
    result = []; // 结果数组
  for (let i = 0; i < nums.length; i++) {
    const item = nums[i];
    // 判断 是否 连续;不连续就要添加区间
    if (item !== nums[i + 1] - 1) {
      // 是否是单个数字;然后添加区间
      result.push(index === i ? `${item}` : `${nums[index]}->${item}`);
      index = i + 1; // 记录下一个开始的索引
    }
  }
  return result;
};

console.log(summaryRanges([0, 1, 2, 4, 5, 7])); // ["0->2", "4->5", "7"]

6、栈

  • 栈:储存了顺序结构
  • 题目1:判断字符串是不是有效括号
// 方式1,所有括号都有配对的另一半,把配对子都放进去;
// 如果栈最后一个配对上了。说明他是偏向内部的完整括号,那么删除,也不再增加配对子;
// 栈为空,添加配对子;没有匹配上,添加配对子;
var isValid = function (s) {
  // 偶数位
  if (s.length % 2 !== 0 || s.length === 0) return false;
  const configObj = {
    "(": ")",
    "{": "}",
    "[": "]"
  };
  const stack = [];
  for (let i = 0; i < s.length; i++) {
    const char = s[i];
    const target = configObj[char];
    if (stack.length > 0) {
      // 检测是否配对
      if (stack[stack.length - 1] === char) {
        stack.pop();
      } else {
        // 存配对子
        stack.push(target);
      }
    } else {
      // 存配对子
      stack.push(target);
    }
  }
  return stack.length === 0;
};
console.log(isValid("([]{})")); // true
// console.log(isValid("([)")); // false

方式2,只关注左侧括号,只存储左侧括号对应的配对子

// 碰到左侧括号就放入配对子,
// 否则检查最后一个元素是否配对,
// 配对上了就删除最后一个元素
var isValid = function (s) {
  // 偶数位
  if (s.length % 2 !== 0 || s.length === 0) return false;
  const configObj = {
    "(": ")",
    "{": "}",
    "[": "]"
  };
  const stack = [];
  for (let i = 0; i < s.length; i++) {
    const char = s[i];
    const target = configObj[char];
    if (target) {
      // 放入配对子
      stack.push(target);
    } else {
      //  右侧括号 对应
      if (stack[stack.length - 1] !== char) {
        return false;
      }
      // 配对上了 必须删除一个
      stack.pop();
    }
  }
  return stack.length === 0;
};
console.log(isValid("([]{})")); // true
// console.log(isValid("([)")); // false

7、进制求和

  • 进制求和:模仿进制
  • 题目1:二进制求和
var addBinary = function (a, b) {
  const maxLength = Math.max(a.length, b.length);
  let carry = 0; // 进位
  let result = ""; // 结果
  for (let i = 0; i < maxLength; i++) {
    const num1 = a[a.length - 1 - i] || 0; // 取最后一位,不存在则补0
    const num2 = b[b.length - 1 - i] || 0;
    const count = parseInt(num1) + parseInt(num2) + carry; // 加法
    result = (count % 2) + result; // 取最后一位
    carry = count >= 2 ? 1 : 0; // 进位
  }
  return carry === 1 ? 1 + result : result;
};

console.log(addBinary("11", "1")); // "100"

8、数学

  • 题目1:数字加一,[1, 2, 9]=>[1, 3, 0]
  • 熟练使用自增和自减
var plusOne = function (digits) {
  const length = digits.length;
  let carry = 1;
  for (let i = length - 1; i >= 0; i--) {
    const num = digits[i];
    // 处理的位置
    // 进制为10 检查是否进制
    // 不进制,原位置加数
    if (num + carry === 10) {
      digits[i] = 0;
      carry = 1;
    } else {
      digits[i] = num + carry;
      carry = 0;
      break; // 找到第一个不为9的就退出, 不用再加
    }
  }
  // 如果超出进制,在最前面再加一
  if (carry === 1) {
    digits.unshift(1);
  }
  return digits;
};
console.log(plusOne([1, 2, 9])); // [1, 2, 4]

进制时,循环索引可以自增,也可以自减;都可以定位到最后一位

const arr = [1, 2, 9];
// 自增
for (let i = 0; i < arr.length; i++) {
  // 处理的位置
  const index = length - 1 - i;
  const num = digits[index];
}
// 自减
for (let i = arr.length - 1; i >= 0; i--) {
  const num = arr[i];
}

9、动态规划

  • 题目1:假设你正在爬楼梯。需要 n 阶你才能到达楼顶。每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?

var climbStairs = function (n) {
  if (n === 1) return 1;
  if (n === 2) return 2;
  let prev1 = 1;
  let prev2 = 2; // 两种方案 1+1,2
  let result = 0;
  // 由于最后一步只能爬1或2,
  // 所以只需要计算前两步的和,相当于分类讨论;
  // 比如假设最后一步是1,那就是在n-1的位置,爬1个台阶,
  // 最后一步是2,那么就在n-2的位置,爬2个台阶;
  // f(n) = f(n-1) + f(n-2)
  // 如果可以爬1\2\3,则f(n) = f(n-1) + f(n-2) + f(n-3)
  for (let i = 3; i <= n; i++) {
    result = prev1 + prev2;
    prev1 = prev2;
    prev2 = result;
  }
  return result;
};

console.log(climbStairs(5)); // 8

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2330410.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

局域网:电脑或移动设备作为主机实现局域网访问

电脑作为主机 1. 启用电脑的网络发现、SMB功能 2. 将访问设备开启WIFI或热点&#xff0c;用此电脑连接&#xff1b;或多台设备连接到同一WIFI 3. 此电脑打开命令行窗口&#xff0c;查看电脑本地的IP地址 Win系统&#xff1a;输入"ipconfig"&#xff0c;回车后如图 4.…

小型园区组网图

1. 在小型园区中&#xff0c;S5735-L-V2通常部署在网络的接入层&#xff0c;S8700-4通常部署在网络的核心&#xff0c;出口路由器一般选用AR系列路由器。 2. 接入交换机与核心交换机通过Eth-Trunk组网保证可靠性。 3. 每个部门业务划分到一个VLAN中&#xff0c;部门间的业务在C…

数据分享:汽车测评数据

说明&#xff1a;如需数据可以直接到文章最后关注获取。 1.数据背景 Car Evaluation汽车测评数据集是一个经典的机器学习数据集&#xff0c;最初由 Marko Bohanec 和 Blaz Zupan 创建&#xff0c;并在 1997 年发表于论文 "Classifier learning from examples: Common …

批量将 txt/html/json/xml/csv 等文本拆分成多个文件

我们的文本文件太大的时候&#xff0c;我们通常需要对文本文件进行拆分&#xff0c;比如按多少行一个文件将一个大的文本文件拆分成多个小的文本文件。这样我们在打开或者传输的时候都比较方便。今天就给大家介绍一种同时对多个文本文件进行批量拆分的方法&#xff0c;可以快速…

Vue3 路由权限管理:基于角色的路由生成与访问控制

Vue3 路由权限管理&#xff1a;基于角色的路由生成与访问控制 一、核心概念 1.1 大致流程思路&#xff1a; 用户在登录完成的时候&#xff0c;后端给出一个此登录用户对应的角色名字&#xff0c;此时可以将这个用户的角色存起来(vuex/pinia)中&#xff0c;在设置路由时的met…

忘记mysql的root用户密码(已解决)

1、打开数据库可视化界面&#xff08;比如MySQL workbench&#xff09; 2、执行select host,user,authentication_string from mysql.user; 3、把‘authentication_string’下面的字段 复制到MD5在线解密网页中&#xff08;比如md5在线解密&#xff09;

ubuntu 20.04 编译和运行SC-LeGo-LOAM

1.搭建文件目录和clone代码 mkdir -p SC-LeGo-LOAM/src cd SC-LeGo-LOAM/src git clone https://github.com/AbangLZU/SC-LeGO-LOAM.git cd .. 2.修改代码 需要注意的是原作者使用的是Ouster OS-64雷达&#xff0c;需要更改utility.h文件中适配自己的雷达类型&#xff0c;而…

CentOS 7安装hyperscan

0x00 前言 HyperScan是一款由Intel开发的高性能正则表达式匹配库&#xff0c;专为需要快速处理大量数据流的应用场景而设计。它支持多平台运行&#xff0c;包括Linux、Windows和macOS等操作系统&#xff0c;并针对x86架构进行了优化&#xff0c;以提供卓越的性能表现。HyperSc…

UE5 Simulation Stage

首先将Grid2D创建出来&#xff0c;然后设置值&#xff0c;Grid2D类似于在Niagara系统中的RenderTarget2D&#xff0c;可以进行绘制&#xff0c;那么设置大小为512 * 512 开启Niagara粒子中的Simulation Stage 然后开始编写我们的自定义模块 模块很简单&#xff0c;TS就是Textur…

Swift 解 LeetCode 250:搞懂同值子树,用递归写出权限系统检查器

文章目录 前言问题描述简单说&#xff1a;痛点分析&#xff1a;到底难在哪&#xff1f;1. 子树的概念搞不清楚2. 要不要“递归”&#xff1f;递归从哪开始&#xff1f;3. 怎么“边遍历边判断”&#xff1f;这套路不熟 后序遍历 全局计数器遍历过程解释一下&#xff1a;和实际场…

增益调度控制 —— 理论、案例与交互式 GUI 实现

目录 增益调度控制 —— 理论、案例与交互式 GUI 实现一、引言二、增益调度控制的基本原理三、数学模型与公式推导四、增益调度控制的优势与局限4.1 优势4.2 局限五、典型案例分析5.1 案例一:航空飞行控制中的增益调度5.2 案例二:发动机推力控制中的增益调度5.3 案例三:化工…

关于OEC/OEC-turbo刷机问题的一些解决方法(2)——可能是终极解决方法了

前面写了两篇关于OEC/OEC-turbo刷机问题的文章了&#xff0c;从刷机过程、刷机中遇到的问题&#xff0c;以及遇到最多但始终无法有效解决的下载boot失败的问题的剖析&#xff0c;最近确实也做了一些工作&#xff0c;虽然没有最终解决&#xff0c;但也算是这系列文章里面阶段性的…

瓦片数据合并方法

影像数据 假如有两份影像数据 1.全球底层影像0-5级别如下&#xff1a; 2.局部高清影像数据级别9-14如下&#xff1a; 合并方法 将9-14文件夹复制到全球底层0-5的目录下 如下&#xff1a; 然后合并xml文件 使得Tileset设置到最高级&#xff08;包含所有级别&#xff09;&…

第16届蓝桥杯单片机模拟试题Ⅰ

试题 代码 sys.h #ifndef __SYS_H__ #define __SYS_H__#include <STC15F2K60S2.H> //onewire.c float getT(); //sys.c extern unsigned char UI; extern bit touch_mode; extern float jiaozhun; extern float canshu; extern float temper; void init74hc138(unsigned…

mac 卸载流氓软件安全助手

之前个人电脑在公司使用过一段时间&#xff0c;为了使用网线联网安装了公司指定的 联软上网助手&#xff0c;谁知安装容易卸载难&#xff0c;后来找运维来卸载&#xff0c;输入管理员密码后&#xff0c;也无反应&#xff0c;最后不了了之了&#xff0c;这个毒瘤软件长期在后台驻…

⭐算法OJ⭐滑动窗口最大值【双端队列(deque)】Sliding Window Maximum

文章目录 双端队列(deque)详解基本特性常用操作1. 构造和初始化2. 元素访问3. 修改操作4. 容量操作 性能特点时间复杂度&#xff1a;空间复杂度&#xff1a; 滑动窗口最大值题目描述方法思路解决代码 双端队列(deque)详解 双端队列(deque&#xff0c;全称double-ended queue)是…

沧州铁狮子

又名“镇海吼”&#xff0c;是中国现存年代最久、形体最大的铸铁狮子&#xff0c;具有深厚的历史文化底蕴和独特的艺术价值。以下是关于沧州铁狮子的详细介绍&#xff1a; 历史背景 • 铸造年代&#xff1a;沧州铁狮子铸造于后周广顺三年&#xff08;953年&#xff09;&#…

Python•判断循环

ʕ⸝⸝⸝˙Ⱉ˙ʔ ♡ 判断🍰常用的判断符号(比较运算符)andor括号notin 和 not inif-elif-else循环🍭计数循环 forrange()函数简易倒计时enumerate()函数zip()函数遍历列表遍历元组遍历字符串遍历字典条件循环 while提前跳转 continue跳出循环 break能量站😚判断🍰 …

【力扣hot100题】(060)分割回文串

每次需要判断回文串&#xff0c;这点比之前几题回溯题目复杂一些。 还有我怎么又多写了循环…… class Solution { public:vector<vector<string>> result;string s;bool palindromic(string s){for(int i0;i<s.size()/2;i) if(s[i]!s[s.size()-1-i]) return …

C++---day7

#include <iostream> #include <cstring> #include <cstdlib> #include <unistd.h> #include <sstream> #include <vector> #include <memory>using namespace std;class Stu { private:public:};// 自定义 vector 类&#xff0c;重…