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;
};

 

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