leetcode刷題記錄(11)

 

 

1.存在重複元素 *簡單

題目:

給定一個整數數組,判斷是否存在重複元素。

如果任意一值在數組中出現至少兩次,函數返回 true 。如果數組中每個元素都不相同,則返回 false 。

思路:首先是用map來記錄

/**
 * @param {number[]} nums
 * @return {boolean}
 */
var containsDuplicate = function(nums) {
    let map={}
for(let i=0,l=nums.length;i<l;i++){
    if(map[nums[i]]){
        return true
    }else{
        map[nums[i]]=1
    }
};
return false
};

還可以利用Set對象的特點

/**
 * @param {number[]} nums
 * @return {boolean}
 */
var containsDuplicate = function(nums) {
return new Set(nums).size!==nums.length
};

藉助indexOf方法(這種方法最慢,並且慢得多)

var containsDuplicate = function(nums) {

for(let i=0,l=nums.length;i<l;i++){
if(nums.indexOf(nums[i])!==i)return true
};
return false
};

還是用Set

/**
 * @param {number[]} nums
 * @return {boolean}
 */
var containsDuplicate = function(nums) {
const set=new Set();
for(let i=0,l=nums.length;i<l;i++){
if(set.has(nums[i]))return true
set.add(nums[i])
};
return false
}

2.存在重複元素 II  *簡單

題目:

給定一個整數數組和一個整數 k,判斷數組中是否存在兩個不同的索引 i 和 j,使得 nums [i] = nums [j],並且 i 和 j 的差的 絕對值 至多爲 k。

思路:還是先來簡單的,用map記錄

/**
 * @param {number[]} nums
 * @param {number} k
 * @return {boolean}
 */
var containsNearbyDuplicate = function(nums, k) {
  let map = {};
  for (let i = 0, l = nums.length; i < l; i++) {
    if (map[nums[i]] !== undefined) {
      if (i - map[nums[i]] <= k) return true;
    }
    map[nums[i]] = i;
  }
  return false;
};

另一個思路:設想一滑動窗口,窗口寬度固定,然後往左滑,判斷新添加的元素是否是k,如果是k且窗口已有,則返回true,如果窗口寬度大於k,則刪除set的第一個元素

/**
 * @param {number[]} nums
 * @param {number} k
 * @return {boolean}
 */
var containsNearbyDuplicate = function(nums, k) {
    const set = new Set();
    for(let i = 0; i < nums.length; i++) {
        if(set.has(nums[i])) {
            return true;
        }
        set.add(nums[i]);
        if(set.size > k) {
            set.delete(nums[i - k]);
        }
    }
    return false;
};

3.翻轉二叉樹 *簡單

題目:翻轉一棵二叉樹。

思路:遞歸,或者用數組迭代,很簡單,無非是遍歷順序的不同

/**
 * @param {TreeNode} root
 * @return {TreeNode}
 */
var invertTree = function(root) {
    if(root === null) return null;
    invertTree(root.left);
    invertTree(root.right);
    [root.left,root.right] = [root.right,root.left];
    return root;
};
/**
 * @param {TreeNode} root
 * @return {TreeNode}
 */
var invertTree = function(root) {
  if (root && (root.left || root.right)) {
    let temp = root.left;
    root.left = invertTree(root.right);
    root.right = invertTree(temp);
  }
  return root;
};
 */
/**
 * @param {TreeNode} root
 * @return {TreeNode}
 */
var invertTree = function(root) {
    let queue = [root];
    while(queue.length > 0){
        let cur = queue.pop();
        if(cur === null) continue;
        [cur.left,cur.right] = [cur.right,cur.left];
        queue.unshift(cur.left);
        queue.unshift(cur.right);
    }
    return root;
};

4.兩數相加 *中等

題目:

給出兩個 非空 的鏈表用來表示兩個非負的整數。其中,它們各自的位數是按照 逆序 的方式存儲的,並且它們的每個節點只能存儲 一位 數字。

如果,我們將這兩個數相加起來,則會返回一個新的鏈表來表示它們的和。

您可以假設除了數字 0 之外,這兩個數都不會以 0 開頭。

思路:動態規劃,用尾遞歸的方式實現,按照同樣的順序去遍歷兩個鏈表的每一個節點,如果是null則值爲0,然後後前一位是否要進1

var addTwo = (l1, l2, flag) => {
  if (l1 || l2||flag) {
    let v1 = 0;
    let v2 = 0;
    if (l1) {
      v1 = l1.val;
      l1 = l1.next;
    }
    if (l2) {
      v2 = l2.val;
      l2 = l2.next;
    }
    const v = (flag ? 1 : 0) + v1 + v2;
    flag = v > 9;
    const cv = new ListNode(v % 10);
    cv.next = addTwo(l1, l2, flag);
    return cv;
  } else {
    return null;
  }
};
var addTwoNumbers = function (l1, l2) {
  return addTwo(l1, l2, false);
};

然後把flag去掉,直接給l1的下一個節點+1,就只需要一個函數遞歸完成

var addTwoNumbers = function (l1, l2) {
  if (l1 || l2) {
    let v1 = 0;
    let v2 = 0;
    if (l1) {
      v1 = l1.val;
      l1 = l1.next;
    }
    if (l2) {
      v2 = l2.val;
      l2 = l2.next;
    }
    const v = v1 + v2;
    const flag = v > 9;
    if (flag) {
      if (l1) {
        l1.val += 1;
      } else {
        l1 = new ListNode(1);
      }
    }
    const cv = new ListNode(v % 10);
    cv.next = addTwoNumbers(l1, l2);
    return cv;
  } else {
    return null;
  }
};

迭代實現,思路一樣

/**
 * @param {ListNode} l1
 * @param {ListNode} l2
 * @return {ListNode}
 */

var addTwoNumbers = function (l1, l2) {
  let flag = false;
  let res = null;
  let cur = null;
  while (l1 || l2 || flag) {
    let v1 = 0;
    let v2 = 0;
    if (l1) {
      v1 = l1.val;
      l1 = l1.next;
    }
    if (l2) {
      v2 = l2.val;
      l2 = l2.next;
    }
    const v = (flag ? 1 : 0) + v1 + v2;
    flag = v > 9;
    const cv = new ListNode(v % 10);
    if (!res) {
      res = cur = cv;
    } else {
      cur.next = cv;
      cur = cv;
    }
  }
  return res;
};

5.無重複字符的最長子串 *中等

題目:給定一個字符串,請你找出其中不含有重複字符的 最長子串 的長度。

思路:最簡單的思路,用一個數組記錄之前的字符,二層嵌套的循環,遍歷每一個可能的字符,然後比較最大值

/**
 * @param {string} s
 * @return {number}
 */
var lengthOfLongestSubstring = function(s) {
  let stack = [];
  let res = 0;
  for (let i = 0, l = s.length; i < l; i++) {
    for (let j = i; j < l && l  - i > res; j++) {
      if (stack.includes(s[j])) {
        res = stack.length > res ? stack.length : res;
        stack = [];
        break;
      } else {
        stack.push(s[j]);
      }
    }
    res = stack.length > res ? stack.length : res;
    stack = [];
  }
  return res;
};

優化:當我們遇到重複的字符串時,找到重複的那個字符的下標,然後從它的下一個下標開始遍歷,這樣就不會重複遍歷了

/**
 * @param {string} s
 * @return {number}
 */
var lengthOfLongestSubstring = function(s) {
  let stack = [];
  let res = 0;
  for (let i = 0, l = s.length; i < l; i++) {
    if (stack.includes(s[i])) {
      res = stack.length > res ? stack.length : res;
      const x = stack.indexOf(s[i]);
      stack.splice(0, x + 1);
      stack.push(s[i]);
    } else {
      stack.push(s[i]);
    }
  }
  res = stack.length > res ? stack.length : res;
  return res;
};

優化:類用一個map記錄每個字符出現的位置,遇到重複的就比較長度,然後更新該字符的值

/**
 * @param {string} s
 * @return {number}
 */
var lengthOfLongestSubstring = function(s) {
    let map = new Map(), max = 0
    for(let i = 0, j = 0; j < s.length; j++) {
        if(map.has(s[j])) {
            i = Math.max(map.get(s[j]) + 1, i)
        }
        max = Math.max(max, j - i + 1)
        map.set(s[j], j)
    }
    return max
};

6.最長迴文子串 *中等

思路:暴力解法,雙重遍歷,找到最長的那個

/**
 * @param {string} s
 * @return {string}
 */
var isStr = (s) => {
  while (s.length > 1) {
    if (s[0] == s[s.length - 1]) {
      s = s.substring(1, s.length - 1);
    } else {
      return false;
    }
  }
  return true;
};
var longestPalindrome = function (s) {
  let res = "";
  let end = s.length;
  for (let i = 0; i < end; i++) {
    for (let j = end; j > res.length + i; j--) {
      if (isStr(s.substring(i, j))) {
        if (j - i > res.length) {
          res = s.substring(i, j);
        }
      }
    }
  }
  return res;
};

優化:動態規劃。

如果一個字符串是迴文串,那麼它去掉首尾兩個字符也是迴文串。同理,一個迴文串如果首尾各擴展1個字符,且擴展的字符相同,那麼新

的字符串也是迴文串

/**
 * @param {string} s
 * @return {string}
 */
var isStr = (s) => {
  while (s.length > 1) {
    if (s[0] == s[s.length - 1]) {
      s = s.substring(1, s.length - 1);
    } else {
      return false;
    }
  }
  return true;
};
var longestPalindrome = function (s) {
  let res = "";
  let end = s.length;
  for (let i = 0; i < end; i++) {
    for (let j = end; j > res.length + i; j--) {
      if (isStr(s.substring(i, j))) {
        if (j - i > res.length) {
          res = s.substring(i, j);
        }
      }
    }
  }
  return res;
};

 優化:我們用遇到的第一個迴文串向兩邊擴展,同時記錄最長字符串,最後得到結果

/**
 * @param {string} s
 * @return {string}
 */

var longestPalindrome = function (s) {
    let result = s[0] || "";
    for (let i = 0; i < s.length; i++) {
        for (let j = 1; j <= 2; j++) { 
            let left = i, right = i + j;
            while(left >= 0 && right < s.length && s[left] === s[right]) {
                left--, right++; 
            };
            let length = right - left - 1; //(right - 1) - (left + 1) + 1
            if (length > result.length) {
                result = s.substr(left + 1, length);
            }
        }
    }
    return result;
};

 

 

 

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