algorithm

Posted on:April 6, 2024 at 07:03 AM
预计阅读时长:8 min read 字数:1599

目录

读算法导论(todo)

2.1 插入排序

leetcode(js)

插入排序

INSERTION-SORT(A)
for j = 2 to A.length
    key = A[j]
    i = j - 1
    while i > 0 and A[i] > key
        A[i+1] = A[i]
        i = i-1
    A[i+1] = key
function insertionSort(arr) {
  for (let j = 1; j < arr.length; j++) {
    let key = arr[j];
    let i = j - 1;
    while (i >= 0 && arr[i] > key) {
      arr[i + 1] = arr[i];
      i = i - 1;
    }
    arr[i + 1] = key;
  }
  return arr;
}

简单记录

  1. 两数之和
/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number[]}
 */
var twoSum = function (nums, target) {
  const res = [];
  for (let i = 0; i < nums.length; i++) {
    let newArr = JSON.parse(JSON.stringify(nums));
    newArr.splice(i, 1);
    if (newArr.includes(target - nums[i])) {
      res.push(i);
      break;
    }
  }
  if (res.length > 0) {
    for (let j = 0; j < nums.length; j++) {
      if (nums[j] === target - nums[res[0]] && j !== res[0]) {
        res.push(j);
        break;
      }
    }
  }
  return res;
};
  1. 两数相加
var addTwoNumbers = function (l1, l2) {
  let head = null;
  let temp = head;
  let diff = 0;
  while (l1 || l2) {
    let plus = (l1 ? l1.val : 0) + (l2 ? l2.val : 0) + diff;
    let newVal = plus % 10;
    diff = ~~(plus / 10);
    let node = new ListNode(newVal, null);
    if (!head) {
      head = node;
    }
    if (temp) {
      temp.next = node;
    }
    temp = node;
    l1 = l1 ? l1.next : null;
    l2 = l2 ? l2.next : null;
  }
  if (diff > 0) {
    let node = new ListNode(diff, null);
    if (temp) {
      temp.next = node;
    }
  }
  return head;
};
var addTwoNumbers = function (l1, l2) {
  const dummy = new ListNode(0);
  let current = dummy;
  let carry = 0;

  while (l1 || l2 || carry) {
    const v1 = l1 ? l1.val : 0;
    const v2 = l2 ? l2.val : 0;

    const sum = v1 + v2 + carry;
    carry = Math.floor(sum / 10);

    current.next = new ListNode(sum % 10);
    current = current.next;

    if (l1) l1 = l1.next;
    if (l2) l2 = l2.next;
  }

  return dummy.next;
};

3.最长无重复子串长度

var lengthOfLongestSubstring = function (s) {
  let max = 0;
  let left = 0;
  const len = s.length;
  const map = new Array(128).fill(-1);
  for (let right = 0; right < len; right++) {
    const charCode = s[right].charCodeAt(0);
    if (map[charCode] >= left) {
      left = map[charCode] + 1;
    }
    map[charCode] = right;
    const currentLength = right - left + 1;
    if (currentLength > max) {
      max = currentLength;
    }
  }
  return max;
};

优化代码

var lengthOfLongestSubstring = function (s) {
  const len = s.length;
  if (len <= 1) return len;

  let max = 0;
  let left = 0;
  const map = new Int32Array(128).fill(-1); // 使用 Int32Array 替代普通数组
  let charCode;

  for (let right = 0; right < len; right++) {
    // 提前终止:剩余可能的最大窗口不超过当前 max
    if (len - left <= max) break;

    charCode = s[right].charCodeAt(0);

    // 如果字符在窗口内出现过,移动左指针
    if (map[charCode] >= left) {
      left = map[charCode] + 1;
    }

    // 更新字符的最新位置
    map[charCode] = right;

    // 计算当前窗口长度并更新最大值
    const currentLength = right - left + 1;
    if (currentLength > max) {
      max = currentLength;
    }
  }

  return max;
};

简化后

var lengthOfLongestSubstring = function (s) {
  const n = s.length;
  if (n <= 1) return n;
  let max = 0,
    l = 0,
    map = new Int32Array(128).fill(-1);
  for (let r = 0; r < n && n - l > max; r++) {
    const c = s[r].charCodeAt(0);
    if (map[c] >= l) l = map[c] + 1;
    map[c] = r;
    max = Math.max(max, r - l + 1);
  }
  return max;
};

5.最长回文子串

704.二分查找

var search = function (nums, target) {
  let res = -1;
  let i = 0,
    j = nums.length - 1;
  //这一步经常出错
  while (i <= j) {
    let k = Math.floor((i + j) / 2);
    if (target < nums[k]) {
      j = k - 1;
    } else if (target > nums[k]) {
      i = k + 1;
    } else {
      res = k;
      return res;
    }
  }
  return res;
};

https://www.hello-algo.com/

快慢指针判断链表有环 快指针走3步,一定会相遇吗

数学原理分析

基本设定

慢指针每次走1步

快指针每次走k步(k > 1)

环的长度为n

相对速度分析

每一轮快指针相对慢指针前进了(k-1)步

这个相对运动可以看作是以(k-1)的速度在环中移动

相遇条件

设从进入环后经过t次移动

要相遇必须满足:(k-1)t ≡ 0 (mod n)

即:(k-1)t必须是环长n的整数倍

具体分析k=3的情况

当k=3时:
(k-1)t ≡ 0 (mod n)
2t ≡ 0 (mod n)

这意味着: 如果n是奇数,则t必须是n的倍数 如果n是偶数,则t必须是n/2的倍数

如果快指针每次走3步,慢指针每次走1步,在有环链表中不一定会相遇。这与传统的快指针走2步的情况不同。

让我解释原因: 快指针走2步的情况(一定相遇): 假设慢指针走了k步,快指针就走了2k步 两者的距离差每次增加1步 在环中,这个差值会以环的长度为周期循环 终会出现差值等于环的长度的情况,即相遇 快指针走3步的情况(不一定相遇): 假设环的长度为n 每一轮,快指针比慢指针多走2步 如果n能被2整除,那么可能永远错过相遇点 举个具体例子:

环长度为4的情况:
位置编号:0,1,2,3(然后回到0)

第0次移动:慢=0,快=0
第1次移动:慢=1,快=3
第2次移动:慢=2,快=2
第3次移动:慢=3,快=1
第4次移动:慢=0,快=0(回到初始状态)

在这种情况下,快慢指针会相遇。 但如果环长度为5:

环长度为5的情况:
位置编号:0,1,2,3,4(然后回到0)

第0次移动:慢=0,快=0
第1次移动:慢=1,快=3
第2次移动:慢=2,快=1
第3次移动:慢=3,快=4
第4次移动:慢=4,快=2
第5次移动:慢=0,快=0(回到初始状态)

这形成了一个周期性模式:

相对位置差依次为:0→2→4→1→3→0

这个序列会不断重复

但永远不会出现相对位置差为0的情况(除了回到初始状态)

数学证明

对于k=3的情况:

1.每次移动后的相对距离:d = (3t - t) mod n = 2t mod n

2.要相遇,必须有:2t ≡ 0 (mod n)

3.当n为奇数时,这个方程只在t是n的倍数时成立

4.这意味着指针必须完整地走完n个周期才能相遇

结论

k=2是最优的选择,因为:

相对速度为1,保证能遍历环中每个位置

不会跳过可能的相遇点

k>2时:

相对速度可能与环长形成特殊关系

导致某些位置永远无法到达

增加了不相遇的可能性