IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 代码随想录算法训练营006| 1. 两数之和,202. 快乐数,242.有效的字母异位词,349. 两个数组的交集 -> 正文阅读

[数据结构与算法]代码随想录算法训练营006| 1. 两数之和,202. 快乐数,242.有效的字母异位词,349. 两个数组的交集

1. 两数之和

题目链接:https://leetcode-cn.com/problems/two-sum/

解题思路

1. 暴力求解

算法时间复杂度 O(n^2)
两层循环,外层循环枚举(或称作选中一个标杆),内层循环从枚举值之后开始遍历,计算两数的和是否等于target。如果找到了两个数,那么返回这两个数的下标;

代码

/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number[]}
 */
var twoSum = function (nums, target) {
  for (let i = 0; i < nums.length; i++) {
    for (let j = i + 1; j < nums.length; j++) {
      if (nums[i] + nums[j] === target) {
        return [i, j];
      }
    }
  }
  return [];
};
function twoSum(nums: number[], target: number): number[] {
  for (let i = 0; i < nums.length; i++) {
    for (let j = i + 1; j < nums.length; j++) {
      if (target === nums[i] + nums[j]) {
        return [i, j];
      }
    }
  }
  return [];
}

2. 哈希表求解

这道题最优的做法时间复杂度是 O(n)。
顺序遍历数组,对每?个元素a, 用target-nums[i]得到b, 若b存在于map中,直接返回 2 个数字的下标即可。如果b不存在, 就把a作为key, a的下标作为value存?map中,等待扫到“另?半”数字的时候,再取出来返回结果。

代码

/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number[]}
 */
var twoSum = function (nums, target) {
  let map = new Map();
  for (let i = 0; i < nums.length; i++) {
    if (map.has(target - nums[i])) {
      return [map.get(target - nums[i]), i];
    }
    map.set(nums[i], i);
  }
  return [];
};
function twoSum(nums: number[], target: number): number[] {
  let map = new Map();

  for (let i = 0; i < nums.length; i++) {
    if (map.has(target - nums[i])) {
      return [i, map.get(target - nums[i])];
    }
    map.set(nums[i], i);
  }
  return [];
}

202. 快乐数

题目链接:https://leetcode-cn.com/problems/happy-number/

解题思路

使用一个map存储计算过的数字,如果目前的数字已经计算过,表示死循环出现,return false。持续计算到 1 return true 或是死循环出现return false
范例:判断 4 是不是 happy number

4 ^ 2 = 16
1 ^ 2 + 6 ^ 2 = 37
3 ^ 2 + 7 ^ 2 = 58
...
... = 20
2 ^ 2 + 0 = 4

4 重复出现,因此进入死循环

1. 哈希表

代码

/**
 * @param {number} n
 * @return {boolean}
 */
var isHappy = function (n) {
  // map存储计算过的数字
  let map = new Map();

  // 如果nap里面出现过这个数字 或 数字 = 1,停止循环
  while (!map.has(n) && n !== 1) {
    map.set(n, n);
    // 单纯的计算每一个位数的平方和
    n.toString()
      .split("")
      .forEach((item, index) => {
        if (index === 0) {
          n = 0;
        }
        n += item * item;
      });
    n = parseInt(n);
  }
  return n === 1;
};

242.有效的字母异位词

题目链接:https://leetcode.cn/problems/valid-anagram/

解题思路

1. 转化为顺序字符串

代码

/**
 * @param {string} s
 * @param {string} t
 * @return {boolean}
 */
var isAnagram = function (s, t) {
  return s.split("").sort().join("") == t.split("").sort().join("");
};
var isAnagram = function (s, t) {
  return (
    s.length == t.length && [...s].sort().join("") === [...t].sort().join("")
  );
};

2.

定义一个数组叫做 record 用来上记录字符串 s 里字符出现的次数。
需要把字符映射到数组也就是哈希表的索引下表上,因为字符 a 到字符 z 的 ASCII 是 26 个连续的数值,所以字符 a 映射为下表 0,相应的字符 z 映射为下表 25。
再遍历 字符串 s 的时候,只需要将 s[i] - ‘a’ 所在的元素做+1 操作即可,并不需要记住字符 a 的 ASCII,只要求出一个相对数值就可以了。 这样就将字符串 s 中字符出现的次数,统计出来了。
那看一下如何检查字符串 t 中是否出现了这些字符,同样在遍历字符串 t 的时候,对 t 中出现的字符映射哈希表索引上的数值再做-1 的操作。
那么最后检查一下,record 数组如果有的元素不为零 0,说明字符串 s 和 t 一定是谁多了字符或者谁少了字符,return false。
最后如果 record 数组所有元素都为零 0,说明字符串 s 和 t 是字母异位词,return true。

代码

/**
 * @param {string} s
 * @param {string} t
 * @return {boolean}
 */
var isAnagram = function (s, t) {
  if (s.length !== t.length) return false;
  const record = new Array(26).fill(0);
  const base = "a".charCodeAt();
  for (const i of s) {
    record[i.charCodeAt() - base]++;
  }
  for (const i of t) {
    if (!record[i.charCodeAt() - base]) return false;
    record[i.charCodeAt() - base]--;
  }
  return true;
};

349. 两个数组的交集

题目链接:https://leetcode-cn.com/problems/intersection-of-two-arrays/

解题思路

1. 暴力解法

代码

/**
 * @param {number[]} nums1
 * @param {number[]} nums2
 * @return {number[]}
 */
var intersection = function (nums1, nums2) {
  let len1 = nums1.length;
  let len2 = nums2.length;
  let set = new Set();
  for (let i = 0; i < len1; i++) {
    for (let j = 0; j < len2; j++) {
      if (nums1[i] === nums2[j]) {
        set.add(nums1[i]);
      }
    }
  }
  return Array.from(set);
};

2. 数组遍历

1)先判断nums1nums2长度谁的长度短,遍历最短的数组
2)如果可以在长的数组nums1中找到nums2[i],表示这是交集的数字
2)判断结果数组result是否已经有交集数字,如果没有就新增到结果数组resu1t

时间复杂度为O(m*n)

代码

/**
 * @param {number[]} nums1
 * @param {number[]} nums2
 * @return {number[]}
 */
var intersection = function (nums1, nums2) {
  let len1 = nums1.length;
  let len2 = nums2.length;
  let result = [];

  if (len1 > len2) {
    for (let i = 0; i < len2; i++) {
      if (nums1.includes(nums2[i]) && !result.includes(nums2[i])) {
        result.push(nums2[i]);
      }
    }
  } else {
    for (let i = 0; i < len1; i++) {
      if (nums2.includes(nums1[i]) && !result.includes(nums1[i])) {
        result.push(nums1[i]);
      }
    }
  }
  return result;
};

优化:

我们定义为nums2,如果nums1更短,使用解构赋值进行交换

代码

/**
 * @param {number[]} nums1
 * @param {number[]} nums2
 * @return {number[]}
 */
var intersection = function (nums1, nums2) {
  let len1 = nums1.length;
  let len2 = nums2.length;
  let result = [];

  // 判断nums1,nums2的长度
  [nums1, nums2] = len1 > len2 ? [nums1, nums2] : [nums2, nums1];

  // 只需要遍历较短的数组就行
  for (let i = 0; i < len2; i++) {
    // 如果可以在长的数组中找到目前的值,
    // 而且在结果result中找不到,代表这个值是新的交集
    if (nums1.includes(nums2[i]) && !result.includes(nums2[i])) {
      result.push(nums2[i]);
    }
  }
  return result;
};

4. 使用 set

为了在线性时间内解决这个问题,我们使用集合set这一数据结构,该结构可以提供平均时间复杂度为O(1)

1)将两个数组都转换为集合,然后迭代较小的集合,检查其中的每个元素是否同样存在于较大的集合中

平均情况下,这种方法的时间复杂度为 O(n+m)

代码

/**
 * @param {number[]} nums1
 * @param {number[]} nums2
 * @return {number[]}
 */
var intersection = function (nums1, nums2) {
  let set1 = new Set(nums1);
  let set2 = new Set(nums2);
  let result = new Set();

  [set1, set2] = set1.size > set2.size ? [set1, set2] : [set2, set1];

  for (let item of set2) {
    if (set1.has(item) && !result.has(item)) {
      result.add(item);
    }
  }

  return Array.from(result);
};

5. 数组的 filter 方法

代码

/**
 * @param {number[]} nums1
 * @param {number[]} nums2
 * @return {number[]}
 */
var intersection = function (nums1, nums2) {
  return Array.from(new Set(nums1.filter((x) => nums2.includes(x))));
};

6. 数组的 filter 方法+set 的 has 方法

代码

/**
 * @param {number[]} nums1
 * @param {number[]} nums2
 * @return {number[]}
 */
var intersection = function (nums1, nums2) {
  let set2 = new Set(nums2);
  return [...new Set(nums1.filter((x) => set2.has(x)))];
};

7. set

代码

/**
 * @param {number[]} nums1
 * @param {number[]} nums2
 * @return {number[]}
 */
var intersection = function (nums1, nums2) {
  // 根据数组大小交换操作的数组
  if (nums1.length < nums2.length) {
    const _ = nums1;
    nums1 = nums2;
    nums2 = _;
  }
  const nums1Set = new Set(nums1);
  const resSet = new Set();
  // for(const n of nums2) {
  //     nums1Set.has(n) && resSet.add(n);
  // }
  // 循环 比 迭代器快
  for (let i = nums2.length - 1; i >= 0; i--) {
    nums1Set.has(nums2[i]) && resSet.add(nums2[i]);
  }
  return Array.from(resSet);
};

8. 双指针

代码

var intersection = function (nums1, nums2) {
  nums1.sort((x, y) => x - y);
  nums2.sort((x, y) => x - y);
  const length1 = nums1.length,
    length2 = nums2.length;
  let index1 = 0,
    index2 = 0;
  const intersection = [];
  while (index1 < length1 && index2 < length2) {
    const num1 = nums1[index1],
      num2 = nums2[index2];
    if (num1 === num2) {
      // 保证加入元素的唯一性
      if (
        !intersection.length ||
        num1 !== intersection[intersection.length - 1]
      ) {
        intersection.push(num1);
      }
      index1++;
      index2++;
    } else if (num1 < num2) {
      index1++;
    } else {
      index2++;
    }
  }
  return intersection;
};
  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-11-05 00:49:39  更:2022-11-05 00:51:09 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/16 13:55:18-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码