头图
This series mainly records LeetCode classic algorithm problem and the process from seeing the problem to solving the answer, and finally multi-thinking expansion. Only as a record of the question and discussion of the idea of solving the problem (I hope everyone can communicate the idea of solving the problem together), and learn the algorithm in the way of watching the leopard!
Recommended books that , 1618dd1bf9ae13, comic algorithm, data structure,

Note: For the convenience of the posted code, there may be multiple logical solutions in one idea. If you need to copy and run, please pay attention to the notes.

Palindrome
Title description:

image.png

Problem disassembly:

Determine whether a string of numbers is a palindrome, and return the value of boolean

  • Palindrome number (Palindrome number refers to the same integer in both positive order (from left to right) and reverse order (from right to left). For example, 121 is a palindrome, but 123 is not.)
Idea 1: traverse the flashback to determine whether it is exactly the same as the original value
var isPalindrome = function(x) {
  if (x < 0) return false;
  // 思路一:正序和倒叙的值是完全一致的则是回文
  // 这里可利用遍历、倒叙、等数组/字符串的原生方法

  // 利用 reverse (76-80ms)
  x = x.toString();
  let reverse_x = x.split("").reverse().join("");
  return x === reverse_x;

  // 遍历 (60-84ms)
  x = x.toString().split("");
  let reverse_x = '';
  for (let i = 0; i < x.length; i++) {
    const ele = x[i];
    reverse_x = ele + reverse_x;
  }
  return reverse_x === x.join('');
};
Idea 2: based on the number characteristics of the base replacement, since it is a number, you can use the base replacement (60-92ms)
// 思路二:既然是数字可以利用进制替换(60-92ms)
var isPalindrome = function(x) {
  let reverse_x = 0;
  for (let i = x; i >= 1; i = Math.floor(i / 10)){
    reverse_x = reverse_x * 10 + (i % 10);
  }
  return reverse_x === x;

  // 既然是回文那么我只遍历一半呢
  let reverse_x = 0;
  let center_index,
    minVal = 1;
  let x_leng = x.toString().length;
  center_index = Math.ceil(x_leng / 2);
  minVal = Math.pow(10, center_index);
  for (let i = x; i >= minVal; i = Math.floor(i / 10)) {
    reverse_x = reverse_x * 10 + (i % 10);
  }
  return reverse_x === Math.floor(x / minVal);

  // 利用 which 替换for
  if (x < 0) return false;
  let temp = x;
  let res = 0;
  while (x) {
    res = res * 10 + (x % 10);
    x = Math.floor(x / 10);
  }
  return res == temp;
};

Here, the palindrome is only the number replaced with digits, to determine whether even the single digits are equal; since it is a palindrome, we only traverse the general number to determine whether the first half of the traversal is consistent with the second half of the unprocessed

Combine K ascending linked lists
Title description:

image.png

Problem disassembly:

Combine multiple ascending linked lists into one ascending linked list

Idea 1: Use the way of array traversal
//链表节点实例
function ListNode(val, next) {
     this.val = (val===undefined ? 0 : val)
    this.next = (next===undefined ? null : next)
}

var mergeKLists = function(lists) {
  // 思路一:利用数组的处理方式(不推荐)

  // 亮点:代码简介
  return lists.reduce((p, n) => {
        while (n) {
            p.push(n), n = n.next
        }
        return p
    },[]).sort((a, b) => a.val - b.val).reduceRight((p, n) => (n.next = p, p = n, p), null)

  // 亮点: 条理清晰
  // 1. 想将链表处理成一维数组,
  // 2. 将数组进行排序
  // 3. 最后将排序后的数组转换成链表
  let arr = []
  lists.forEach((ele) => {
    function deepLinkedList(list) {
      arr.push(list.val);
      if(list.next){
        deepLinkedList(list.next);
      }
    }
    deepLinkedList(ele)
  });
  arr.sort()
  let arr_list = {};

  function deepList(arr,map) {
    map["val"] = arr[0];
    arr.shift(1);
    map["next"] = arr.length?{}:null;
    if(arr.length){
      deepList(arr, map["next"]);
    }
  }
  deepList(arr, arr_list);
  return arr_list;
};
Idea 2: Linked lists are merged in pairs
function ListNode(val, next) {
     this.val = (val===undefined ? 0 : val)
    this.next = (next===undefined ? null : next)
}

var mergeKLists = function(lists) {
  // 思路二:使用数据结构链表思路:新建一个空白链表以及一个移动的指针指向将要操作的节点上
  // 两两合并
  let ans = null;
  for (let i = 0; i < lists.length; i++) {
    ans = mergeTwoList(ans, lists[i]);
  }
  return ans;

  function mergeTwoList(pHead1, pHead2) {
    let newList = new ListNode();
    let cur = newList;
    while (pHead1 !== null && pHead2 !== null) {
      // 找出更小筛入队列中
      if(pHead1.val < pHead2.val) {
        cur.next = pHead1
        pHead1 = pHead1.next
      } else {
        cur.next = pHead2
        pHead2 = pHead2.next
      }
      cur = cur.next;
    }
    cur.next = pHead1 || pHead2;
    // console.log(newList,cur);
    return newList.next;
  }
};
Test case:
let data = mergeKLists([
   { val: 1, next: { val: 4, next: { val: 5, next: null } } },
   { val: 1, next: { val: 3, next: { val: 4, next: null } } },
   { val: 2, next: { val: 6, next: null } },
]);
K flip list
Title description:

image.png

Problem disassembly:

Return a linked list according to n without a set of flashbacks. If the remaining linked list or the total linked list is less than n bits, keep it as it is

Idea 1: Use a violent way to convert a linked list to an array, and an array to a linked list
var reverseKGroup = function(head, k) {
  if (!k) return;
  // 思路一:利用链表转数组,数组转链表的暴力方式
  let arr = [];
  let len = 0;
  let index = 0;
  function deepLinkedList(list) {
    ++len;
    if (!arr[index]) arr[index] = [];
    arr[index].push(list.val);
    if (len === k) {
      len = 0;
      index += 1;
    }
    if (list.next) {
      deepLinkedList(list.next);
    }
  }
  // 将链表按序转成二维数组
  deepLinkedList(head);
  // 翻转数组并整平
  arr = arr.map((item) => {
    if (item.length >= k) {
      return item.reverse();
    }
    return item;
  });
  arr = [].concat.apply([], arr);

  // 数组在转换成链表
  let arr_list = {};
  function deepList(arr,map) {
    map["val"] = arr[0];
    arr.shift(1);
    map["next"] = arr.length?{}:null;
    if(arr.length){
      deepList(arr, map["next"]);
    }
  }
  deepList(arr, arr_list);
  return arr_list;
};
Idea 1: Use a violent way to convert a linked list to an array, and an array to a linked list
var reverseKGroup = function(head, k) {
  if (!k) return;
  // 思路一:利用链表转数组,数组转链表的暴力方式
  // let arr = [];
  // let len = 0;
  // let index = 0;
  // function deepLinkedList(list) {
  //   ++len;
  //   if (!arr[index]) arr[index] = [];
  //   arr[index].push(list.val);
  //   if (len === k) {
  //     len = 0;
  //     index += 1;
  //   }
  //   if (list.next) {
  //     deepLinkedList(list.next);
  //   }
  // }
  // // 将链表按序转成二维数组
  // deepLinkedList(head);
  // // 翻转数组并整平
  // arr = arr.map((item) => {
  //   if (item.length >= k) {
  //     return item.reverse();
  //   }
  //   return item;
  // });
  // arr = [].concat.apply([], arr);

  // // 数组在转换成链表
  // let arr_list = {};
  // function deepList(arr,map) {
  //   map["val"] = arr[0];
  //   arr.shift(1);
  //   map["next"] = arr.length?{}:null;
  //   if(arr.length){
  //     deepList(arr, map["next"]);
  //   }
  // }
  // deepList(arr, arr_list);
  // return arr_list;

  // 思路二:对链表进行操作
  const hair = new ListNode();
  hair.next = head;
  let pre = hair;
  while (head) {
    let tail = pre;
    // 如果分组的值大于整个链长则直接将链返回
    for (let i = 0; i < k; ++i) {
        tail = tail.next; // 从 0 开始
        if (!tail) {
            return hair.next;
        }
    }
    const nex = tail.next; // 把除去当前组的剩余链表保存
    console.log("倒叙前", head, tail);
    [head, tail] = myReverse(head, tail);
    // 把子链表重新接回原链表
    console.log("倒叙后", head, tail, JSON.stringify(pre));
    pre.next = head;
    tail.next = nex;
    console.log(JSON.stringify(pre), nex, tail);
    pre = tail;
    head = tail.next;
  }
  console.log("结果:", hair.next === head, head, JSON.stringify(hair));
  return hair.next;
};
Idea 2: Group and flip the linked list
var reverseKGroup = function(head, k) {
  if (!k) return;
 
  // 思路二:对链表进行操作
  const hair = new ListNode();
  hair.next = head;
  let pre = hair;
  while (head) {
    let tail = pre;
    // 如果分组的值大于整个链长则直接将链返回
    for (let i = 0; i < k; ++i) {
        tail = tail.next; // 从 0 开始
        if (!tail) {
            return hair.next;
        }
    }
    const nex = tail.next; // 把除去当前组的剩余链表保存
    console.log("倒叙前", head, tail);
    [head, tail] = myReverse(head, tail);
    // 把子链表重新接回原链表
    console.log("倒叙后", head, tail, JSON.stringify(pre));
    pre.next = head;
    tail.next = nex;
    console.log(JSON.stringify(pre), nex, tail);
    pre = tail;
    head = tail.next;
  }
  console.log("结果:", hair.next === head, head, JSON.stringify(hair));
  return hair.next;
};
Test case
reverseKGroup({ val: 1, next: { val: 2, next: { val: 3, next: { val: 4, next: null } } } },2);
Move zero
Title description:

image.png

Problem disassembly:

0 array in the array to the far right, and the other non-zero numbers are in the same order, but they are filled forward

Idea 1: Operate the original array to overwrite and modify, and set the number of zeros to zero, which increases the time complexity
var moveZeroes = function(nums) {
  // 要求: 要求只能原数组操作
  // 思路一: 操作原数组覆盖修改,记录零的个数并置零,时间复杂度增多
  var k = 0;
  for (let i = 0; i < nums.length; i++) {
    if (nums[i] != 0){
      nums[k++] = nums[i];
    }
  }
  for (let j = k; j < nums.length; j++){
    nums[j] = 0;
  }
};
Idea 2: Double pointer thinking (bubbling thinking)
var moveZeroes = function(nums) {
  // 要求: 要求只能原数组操作
  // 思路二:双指针思路(冒泡的思路)
  // 以 0 作为入口 两次循环
  for (let i = 0; i < nums.length; i++) {
    const ele = nums[i];
    if(ele === 0){
      for (let j = i+1; j < nums.length; j++) {
        const ele2 = nums[j];
        if (ele2 !== 0) {
          nums[i] = ele2;
          nums[j] = ele;
          break;
        }
      }
    }
  }

  // 以不等于 0 作为入口;一次循环,并添加一个计数器
  let j = 0;
  for (let i = 0; i < nums.length; i++) {
    //当前元素!=0,就把其交换到左边,等于0的交换到右边
    if (nums[i] != 0) {
      let tmp = nums[i]; // 临时存下来
      nums[i] = nums[j];
      nums[j++] = tmp;
    }
  }

  // 思考一下,如果按上面的思路以等于 0 作为判断依据并只遍历一遍呢?
}
Test case
Course Schedule IV
Title description:

image.png

Question disassembly:

Provide a length of number and have a mapping of the relationship between each number to determine whether a set of relationships conform to

Idea 1: Violent recursive recursive traversal to find out the parent course of each course will time out! Changing the two traversal methods will still time out
var checkIfPrerequisite = function(numCourses, prerequisites, queries) {
  if (!prerequisites.length) {
    return queries.map(() => {
      return false;
    });
  }
  // 思路一: 递归遍历找出各个课程的父课程 会超时! 换了两种遍历途径还是都会超时
  let allQueries = [];
  // prerequisites =  prerequisites.sort((a,b)=>{
  //   return a[0] - b[0]
  // })
  // prerequisites.forEach((ele,index) => {
  //   allQueries.push(ele);
  //   let curPreVal = ele[0];
  //   let curNextVal = ele[1]
    function deep(curVal,oldVal,idx) {
      if (curVal < numCourses) {
        // 这里做个小优化如果吧二维数组的第一个数组排序那每次递归遍历只需要从当前索引的下一个来即可
        for (let i = 0; i < prerequisites.length; i++) {
          const [j,k] = prerequisites[i];
           if (j === curVal) {
             allQueries.push([oldVal===null?curVal:oldVal, k]);
             deep(k, oldVal===null?curVal:oldVal, i);
           }
        }
        // prerequisites.forEach(([j,k]) => {
        //   if (j === curVal) {
        //     allQueries.push([curPreVal, k]);
        //     deep(k);
        //   }
        // });
      }
    }
    // deep(curNextVal,index);
    for (let n = numCourses-1; n >= 0; n--) {
      deep(n,null,0);
    }
  // });
  // console.log(allQueries);
  return queries.map(([i, j]) => {
    return allQueries.some((item) => {
      return JSON.stringify(item) === JSON.stringify([i, j]);
    });
  });
};

Although this is violent, it is also a solution that ordinary students can think of for the first time. All the mapping relationships are collected by recursive traversal, and the target judgment data is compared.

floyed algorithm cleverly uses the shortest path Floyd algorithm to solve
var checkIfPrerequisite = function(numCourses, prerequisites, queries) {
  if (!prerequisites.length) {
    return queries.map(() => {
      return false;
    });
  }

  // 思路二: floyed算法
  let dp = [];
  for (let i = 0; i < numCourses; i++) {
    dp[i] = new Array(numCourses).fill(false);
  }
  // console.log(dp);
  prerequisites.forEach(([i, j]) => (dp[i][j] = true));
  // console.log(dp);
  for (let k = 0; k < numCourses; k++) {
    for (let i = 0; i < numCourses; i++) {
      for (let j = 0; j < numCourses; j++) {
        if((dp[i][k] && dp[k][j])){
          // console.log(k, i, j);
        }
        dp[i][j] = dp[i][j] || (dp[i][k] && dp[k][j]);
      }
    }
  }
  return queries.map(([i, j]) => dp[i][j]);
};
Test case:
// console.log(
//   checkIfPrerequisite(
//     5,
//     [
//       [3, 4],
//       [0, 1],
//       [1, 2],
//       [2, 3],
//     ],
//     [
//       [0, 4],
//       [4, 0],
//       [1, 3],
//       [3, 0],
//     ]
//   )
// );

To be continued~

The programmer ymc who has been on the road!


好久不见
685 声望7 粉丝

努力吃胖,努力健身,快乐打球,快乐code