leetcode刷题记录(13)

1.删除链表中的节点  *简单

题目:请编写一个函数,使其可以删除某个链表中给定的(非末尾)节点,你将只被给定要求被删除的节点。

题目没有描述清楚。函数入参是链表中你要删除的节点。

这题很简单,把next的val值和next属性都覆盖当前的节点就行了

/**
 * @param {ListNode} node
 * @return {void} Do not return anything, modify node in-place instead.
 */
var deleteNode = function(node) {
  node.val = node.next.val;
  node.next = node.next.next;
};

2.有效的字母异位词  *简单

题目:

给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。

这里解释一下,字母异位词,是指两个单词包含的字符完全一样,只是顺序不一样。

/**
 * @param {string} s
 * @param {string} t
 * @return {boolean}
 */
var isAnagram = function(s, t) {
  const l1 = s.length;
  const l2 = t.length;
  if (l1 !== l2) return false;
  for (let i = 0; i < l2; i++) {
    s=s.replace(t[i], "");
  }
  return !s.length;
};

用sort取个巧

/**
 * @param {string} s
 * @param {string} t
 * @return {boolean}
 */
var isAnagram = function(s, t) {
  const l1 = s.length;
  const l2 = t.length;
  if (l1 !== l2) return false;
  const a1 = [...s].sort().join("");
  const a2 = [...t].sort().join("");
  return a1 === a2;
};

用map记录的方式

/**
 * @param {string} s
 * @param {string} t
 * @return {boolean}
 */
var isAnagram = function(s, t) {
  if (s.length !== t.length) {
    return false;
  }
  var m = new Array(26).fill(0);
  for (let i = 0; i < s.length; i++) {
    m[s[i].charCodeAt() - 97]++;
  }
  for (let i = 0; i < t.length; i++) {
    m[t[i].charCodeAt() - 97]--;
    if (m[t[i].charCodeAt() - 97] < 0) {
      return false;
    }
  }
  return true;
};
/**
 * @param {string} s
 * @param {string} t
 * @return {boolean}
 */
var isAnagram = function(s, t) {
  if (s.length !== t.length) {
    return false;
  }
  const map = {};
  for (let i = 0; i < s.length; i++) {
    if (map[s[i]]) {
      map[s[i]]++;
    } else {
      map[s[i]] = 1;
    }
  }
  for (let i = 0; i < t.length; i++) {
    if (!map[t[i]]) return false;
    map[t[i]]--;
    if (map[t[i]] < 0) return false;
  }
  return true;
};

3.整数转罗马数字  *中等

题目:

罗马数字包含以下七种字符: I, V, X, LCD 和 M

字符          数值
I             1
V             5
X             10
L             50
C             100
D             500
M             1000

例如, 罗马数字 2 写做 II ,即为两个并列的 1。12 写做 XII ,即为 X + II 。 27 写做  XXVII, 即为 XX + V + II 。

通常情况下,罗马数字中小的数字在大的数字的右边。但也存在特例,例如 4 不写做 IIII,而是 IV。数字 1 在数字 5 的左边,所表示的数等于大数 5 减小数 1 得到的数值 4 。同样地,数字 9 表示为 IX。这个特殊的规则只适用于以下六种情况:

  • I 可以放在 V (5) 和 X (10) 的左边,来表示 4 和 9。
  • X 可以放在 L (50) 和 C (100) 的左边,来表示 40 和 90。 
  • C 可以放在 D (500) 和 M (1000) 的左边,来表示 400 和 900。

给定一个整数,将其转为罗马数字。输入确保在 1 到 3999 的范围内。

思路:这个和之前的一道题,罗马数字转整数,相当于一个互逆的过程

我们可以观察发现,对于某一位上的数字,如果小于4,是不需要转换的,如果是大于4,则分乘5还是乘10.

如此一来,我们从末尾往前遍历,依次处理遇到的每一个数字,拼接即可。

/**
 * @param {number} num
 * @return {string}
 */
var intToRoman = function(num) {
  const map = {
    1: "I",
    5: "V",
    10: "X",
    50: "L",
    100: "C",
    500: "D",
    1000: "M",
  };
  num = `${num}`;
  const l = num.length;
  let res = "";
  for (let i = 0; i < l; i++) {
    const unit = Math.pow(10, i);
    if (num[l - 1 - i] < 4) {
      res = new Array(+num[l - 1 - i]).fill(map[unit]).join("") + res;
    } else if (num[l - 1 - i] < 9) {
      const basic = map[unit * 5];
      const x = +num[l - 1 - i] - 5;
      const temp = new Array(Math.abs(x)).fill(map[unit]).join("");
      res =( x > 0 ? `${basic}${temp}` : `${temp}${basic}`) + res;
    } else {
      res = `${map[unit]}${map[10 * unit]}${res}`;
    }
  }
  return res;
};

换一种思路,我们把每种单位和对应的罗马字符都罗列,然后用给定的数字减去我们能找到,小于该数字的最大单位,最终直到0

/**
 * @param {number} num
 * @return {string}
 */
var intToRoman = function(num) {
  const key = [1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1];
  const value = [
    "M",
    "CM",
    "D",
    "CD",
    "C",
    "XC",
    "L",
    "XL",
    "X",
    "IX",
    "V",
    "IV",
    "I",
  ];
  let res = "";
  for (let i = 0, l = key.length; i < l; i++) {
    while (num >= key[i]) {
      res += value[i];
      num -= key[i];
    }
  }
  return res;
};

4.三数之和  *中等

题目:

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

注意:答案中不可以包含重复的三元组。

思路:实话说,这题我自己没想出来,是看的别人的解法的。

基础思想还是依次遍历,不同的是,为了去除重复情况,我们需要先排序,排序之后,每次固定一数,然后剩下两个数,用两个指针表示,两个指针一头一尾,类似盛水容器,如果三数相加大于0,则尾部(即最大的值)往左移动,总和肯定减小(这里要注意相同的数),如果小于0,则头部往右移动,总和肯定增大(也要注意相同的数),直到两个指针相遇。

又因为三数相加等于0,所以最小值和最大值肯定是在0的左右两侧,所以用头和尾的乘积是否小于0判断是否要跳过这轮循环

/**
 * @param {number[]} nums
 * @return {number[][]}
 */
var threeSum = function(nums) {
  nums.sort((a,b)=>a-b);
  const l = nums.length;
  const res = [];
  if (nums[0] * nums[l - 1] > 0) return res;
  for (let i = 0; i < l - 2;) {
    if (nums[i] > 0) break;
    let start = i + 1;
    let end = l - 1;
    do {
      if (start >= end || nums[i] * nums[end] > 0) break; 
      let result = nums[i] + nums[start] + nums[end];
      if (result === 0) {
        res.push([nums[i], nums[start], nums[end]]);
      }
      if (result < 0) {
        while (start < end && nums[start] === nums[++start]) {}
      } else {
        while (start < end && nums[end] === nums[--end]) {}
      }
    } while (start < end);
    while (nums[i] === nums[++i]) {}
  }
  return res;
};

5.最接近的三数之和  *中等

题目:

给定一个包括 n 个整数的数组 nums 和 一个目标值 target。找出 nums 中的三个整数,使得它们的和与 target 最接近。返回这三个数的和。假定每组输入只存在唯一答案。

和上一题很类似,每次比较和目标值的差的绝对值即可

/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number}
 */
var threeSumClosest = function(nums, target) {
  nums.sort((a, b) => a - b);
  const l = nums.length;
  let res=nums[0]+nums[1]+nums[2];
  for (let i = 0; i < l - 2; ) {
    let start = i + 1;
    let end = l - 1;
    do {
      let result = nums[i] + nums[start] + nums[end];
      if (Math.abs(result-target)<Math.abs(res-target)) {
        res=result
      }
      if (start >= end ) break; 
      if (result < target) {
        while (start < end && nums[start] === nums[++start]) {}
      } else {
        while (start < end && nums[end] === nums[--end]) {}
      }
    } while (start < end);
    while (nums[i] === nums[++i]) {}
  }
  retu

6.电话号码的字母组合  *中等

题目:

给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。

给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。

思路:其实就是一个排列组合,每个数字对应几种可能的字符,一次把每种可能拼接

/**
 * @param {string} digits
 * @return {string[]}
 */
const map = {
  2: "abc",
  3: "def",
  4: "ghi",
  5: "jkl",
  6: "mno",
  7: "pqrs",
  8: "tuv",
  9: "wxyz",
};
var letterCombinations = function (digits) {
    if(!digits.length)return []
  const res = [""];
  return letterCombinationsAA(digits, res);
};
var letterCombinationsAA = function (digits, res) {
  if (!digits.length) return res;
  const l = res.length;
  for (let i = 0; i < l; i++) {
    const item = res.shift();
    for (const s of map[digits[0]]) {
      res.push(`${item}${s}`);
    }
  }
  return letterCombinationsAA(digits.substring(1), res);
};

用迭代和递归是类似的

/**
 * @param {string} digits
 * @return {string[]}
 */
const map = {
  2: "abc",
  3: "def",
  4: "ghi",
  5: "jkl",
  6: "mno",
  7: "pqrs",
  8: "tuv",
  9: "wxyz",
};
var letterCombinations = function (digits) {
  const l = digits.length;
  if (!l) return [];
  const res = [""];
  for (let i = 0; i < l; i++) {
    const jl = res.length;
    for (let j = 0; j < jl; j++) {
      const item = res.shift();
      for (const s of map[digits[i]]) {
        res.push(`${item}${s}`);
      }
    }
  }
  return res;
};

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章