leetcode刷题记录(1)-中等

1.四数之和

题目:

给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在四个元素 a,b,c 和 d ,使得 a + b + c + d 的值与 target 相等?找出所有满足条件且不重复的四元组。

注意:

答案中不可以包含重复的四元组。

思路:和之前的三数之和类似,再包一个循环

/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number[][]}
 */
var fourSum = function(nums, target) {
  nums.sort((a, b) => a - b)
  let res = []
  let len = nums.length
  for (let i = 0; i < len - 3; i++) {
    if(nums[i] === nums[i - 1]) continue
    for (let j = i + 1; j < len - 2; j++){
      if(res.length > 0){
        let res0 = res[res.length - 1][0]
        let res1 = res[res.length - 1][1]
        if(res0 === nums[i] && res1 === nums[j]) continue
      }
      let left = j + 1
      let right = len - 1
      while(left < right){
        let sum = nums[i] + nums[j] + nums[left] + nums[right]
        if (sum === target) {
          res.push([nums[i], nums[j], nums[left], nums[right]])
          left++
          while(nums[left] === nums[left - 1]) left++
        } else if (sum < target) {
          left++
        } else {
          right--
        }
      }
    }
  }
  return res
};

2.删除链表的倒数第N个节点

题目:给定一个链表,删除链表的倒数第 个节点,并且返回链表的头结点。

思路:把买个节点放进一个数组里,利用数组下标的特性去删除节点

/**
 * @param {ListNode} head
 * @param {number} n
 * @return {ListNode}
 */
var removeNthFromEnd = function(head, n) {
  const res = [];
  let node = head;
  while (node) {
    res.push(node);
    node = node.next;
  }
  if(n===res.length)return head.next
  res[res.length - 1 - n].next = res[res.length - n].next;
  return head;
};

双指针:双指针法的思路就是,让快指针先跑n次,然后两个节点同时跑,直到最后一个节点,这样慢指针的位置就是倒数第N个节点的前一个节点

/**
 * @param {ListNode} head
 * @param {number} n
 * @return {ListNode}
 */
var removeNthFromEnd = function(head, n) {
  const node = new ListNode(1);
  node.next = head;
  let slow = node;
  let fast = node;
  while (n--) {
    fast = fast.next;
  }
  while (fast.next) {
    fast = fast.next;
    slow = slow.next;
  }
  slow.next = slow.next.next;
  return node.next;

};

3.括号生成

题目:数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。

思路:这里要注意的就是有效括号的定义。对任意一个位置,左侧的左括号肯定不会少于右括号。

/**
 * @param {number} n
 * @return {string[]}
 */
var generateParenthesisA = (left, right, pre, res) => {
  if (!pre) {
    generateParenthesisA(--left, right, "(", res);
  } else if (left == right) {
    generateParenthesisA(--left, right, `${pre}(`, res);
  } else if (!left && right == 1) {
    res.push(`${pre})`);
  } else if (!left) {
    generateParenthesisA(left, --right, `${pre})`, res);
  } else {
    generateParenthesisA(--left, right, `${pre}(`, res);
    generateParenthesisA(++left, --right, `${pre})`, res);
  }
  return res;
};
var generateParenthesis = function (n) {
  if (!n) return [];
  const left = n;
  const right = n;
  return generateParenthesisA(left, right, "", []);
};

换成数组的话可以用尾递归达成

/**
 * @param {number} n
 * @return {string[]}
 */
var generateParenthesisA = (left, right, pre, res) => {
  if (!pre) {
    return generateParenthesisA(--left, right, "(", res);
  } else if (left == right) {
    return generateParenthesisA(--left, right, `${pre}(`, res);
  } else if (!left && right == 1) {
    return [`${pre})`];
  } else if (!left) {
    return generateParenthesisA(left, --right, `${pre})`, res);
  } else {
    return generateParenthesisA(
      --left,
      right,
      `${pre}(`,
      res
    ).concat(generateParenthesisA(++left, --right, `${pre})`, res));
  }
};
var generateParenthesis = function (n) {
  if (!n) return [];
  const left = n;
  const right = n;
  return generateParenthesisA(left, right, "");
};

4.两两交换链表中的节点

题目:

给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。

你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。

思路:交换,然后递归

/**
 * @param {ListNode} head
 * @return {ListNode}
 */
var swapPairs = function(head) {
  const node = head;
  if (head && head.next) {
    head = head.next;
    node.next = swapPairs(head.next);
    head.next = node;
  }
  return head;
};

5.下一个排列

题目:

实现获取下一个排列的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列。

如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列)。

必须原地修改,只允许使用额外常数空间。

以下是一些例子,输入位于左侧列,其相应输出位于右侧列。

1,2,3 → 1,3,2
3,2,1 → 1,2,3
1,1,5 → 1,5,1

思路:排列最小值是升序排列,最大值是降序排列。某个排列的下一个排列,其实是从后往前,找到一个某个数,它的前一个数比它小,(说明这个数后面的数都是降序排雷)然后我们从这个数的右边找到比它大的数中的最小者(其实就是升序排列中它的下一个数),交换,交换之后,对后面的数做一升序排列即可。因为后面的数已经是降序排列了,所以只需要做一个镜像交换

/**
 * @param {number[]} nums
 * @return {void} Do not return anything, modify nums in-place instead.
 */
var nextPermutation = function(nums) {
  const length = nums.length;
  for (let j = length - 1; j >= 1; j--) {
    if (nums[j] > nums[j - 1]) {
      for (let i = length - 1; i >= j; i--) {
        if (nums[i] > nums[j - 1]) {
          [nums[i], nums[j - 1]] = [nums[j - 1], nums[i]];
        for (let k = j; k < (j + length - 1) / 2; k++) {
          [nums[k], nums[length - 1+j - k]] = [nums[length - 1 +j- k], nums[k]];
        }
        return nums;
        }
      }
      break;
    }
  }
  return nums.sort((a, b) => a - b);
};

 

你可能感兴趣的:(leetcode-中等难度)