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

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值