[路飞]算法_分隔链表(leetcode.725)

147 阅读3分钟

leetcode.725 题目地址

题目

给你一个头结点为 head 的单链表和一个整数 k ,请你设计一个算法将链表分隔为 k 个连续的部分。

每部分的长度应该尽可能的相等:任意两部分的长度差距不能超过 1 。这可能会导致有些部分为 null 。

这 k 个部分应该按照在链表中出现的顺序排列,并且排在前面的部分的长度应该大于或等于排在后面的长度。

返回一个由上述 k 部分组成的数组。

// exp1
head: 1->2-> 3, k = 5  => ListNode[]: [[1], [2], [3], [], []]
// exp2
head: 1->2->3->4->5->6->7->8->9->10, k=3 => ListNode: [[1,2,3,4],[5,6,7],[8,9,10]]

自己第一遍折腾扣出来的

function splitListToParts2(head, k){
  // 现获取链表长度 len
  let len = 0
  let cur = head
  while (cur) {
    cur = cur.next
    len++
  }

  // 分成k组, 根据题意,我们需要获取每一组的数量最少应该是 num 个
  const num = Math.floor(len / k)
  // 取余rem,记录下会有几个是num + 1个
  let rem = len % k
  // 创建一个结果数组
  const ret = []

  cur = head
  
  // 当 k > len 的时候 直接每一项一个单独的节点,然后len -> k push空节点
  if (k > len) {
    for (let i = 0; i < k; i++) {
      if (cur) {
        ret.push(new ListNode(cur.val))
        cur = cur.next
      } else {
        ret.push(null)
      }
    }
    return ret
  }
  
  // 这里是过去ret的每一项的值
  function getSingle(n) {
    // 用tmp存在当前指针
    let tmp = cur
    // 新建指针来处理截断,
    let p = cur
    // cur 指针 逐步 指向下一个,来获取新的每一项的头节点
    cur = cur.next
    for (let j = 1; j < n; j++) {
      if (!cur) break
      p = p.next
      cur = cur.next
    }
    // 这里截断 是我们的tmp是n个节点
    p.next = null
    return tmp
  }
  // 当前指针指向头节点
  cur = head
  // 我们需要每一项有num个节点,当有余数的时候,我们ret前面rem项的每一项都是n + 1个节点
  // 所以我们先处理这个余数rem的问题
  for (let i = 0; i < rem; i++) {
    // 这里过去到第i项的节点是tmp
    const tmp = getSingle(num + 1)
    // push下
    ret.push(tmp)
  }
  // 来处理基本数量num个的部分, 这里我们还剩下k - rem 项, 上一个步骤我们已经push了rem项
  // 和上面的步骤一样,不同点是
  // 1. 当前指针有可能是空,2. 不为空的时候, 我们每一下都是num个
  for (let i = 0; i < k - rem; i++) {
    if (cur) {
      let tmp = getSingle(num)
      ret.push(tmp)
    } else {
      ret.push(null)
    }
  }
  // 最终得到结果
  return ret
}

看下题解

。。。三个点表示对自己的无语, 代码量就比我少了很多。。

虽然思路是对的,但是处理方式和写法着实差太多了

看完题解我再来重新写一下

function splitListToParts(head, k) {
    let len = 0
    let cur = head
    while(cur) {
        cur = cur.next
        len++
    }
    
    let num = Math.floor(len / k)
    let rem = len % k
    // 到这里都是一样的
    
    // step1
    const ret = Array.from({length: k}).fill(null)
    
    // step2
    for (let i = 0; i < k && cur; i++) {
        // step3
        ret[i] = cur
        
        const n = i < rem ? num + 1 : num // step4
        
        for (let j = 0; j < n; j++) {
            cur = cur.next
        }
        
        const next = cur.next // step5
        cur.next = null
        cur = next
    }
    
    return ret
}

改进学习

  1. step1: 创建符合k项的数组
  2. step2: 结合第一步 处理 K大于长度是的情况
  3. step3:截取前n个节点的方法(我的方法太chun了)
  4. step4:处理每一项的链表长度
  5. step5:结合step3 去除前n个节点的处理

总结

编程能力。。。