链表-链表内指定区间反转

231 阅读1分钟

image.png

方法1: 改变数据结构-转数组
方法2: 双指针
  1. 先把指定区间给找出来,按照正常链表进行反转
  2. 将已经反转好的局部链表与其他节点建立连接,重构链表.如下图,图非原创。

image.png

image.png

function reverseLinkedList(head) {
    let pre = null;
    let cur = head;
    while(cur!=null){
        //Cur_next 指向cur节点的下一个节点
        const Cur_next = cur.next;
        cur.next = pre;
        pre = cur;
        cur = Cur_next ;
    }
}

function reverseBetween( head ,  m ,  n ) {
            //设置虚拟头节点
        let dummyNode = new ListNode(-1);
        dummyNode.next = head;
        
        //1.走left-1步,获取到left的前一个节点
        let pre = dummyNode;
        for(let i=0;i<m-1;i++){
            pre = pre.next;
        }
 
        //2. 走到right节点
        let rigthNode = pre;
        for(let i=0;i<n-m+1;i++){
            rigthNode = rigthNode.next;
        }
 
        //3.截取出要反转的链表
        let leftNode = pre.next;
        let cur = rigthNode.next; // 右节点的下个节点
        //4.切断链接
        pre.next=null; // 切断左节点
        rigthNode.next=null; // 切断右节点
 
    
        //5.反转局部链表
        reverseLinkedList(leftNode);
 
        //6.接回原来的链表
        pre.next = rigthNode;
        leftNode.next = cur;
        return dummyNode.next;
}

时间复杂度:O(N) N是链表总节点数。最坏情况下,需要遍历整个链表 空间复杂度:O(1) 仅使用到常数个变量

方法3: 原地反转 如下图,将5插入到2前面,再将4插入到5前面,依次循环。

image.png

function reverseBetween( head ,  m ,  n ) {
   let dummyNode = new ListNode(-1);
    dummyNode.next =head;
    let pre = dummyNode; // 左节点的前一个节点 上图中就是7
    for(let i=0;i<m-1;i++){
        pre = pre.next;
    }

    let cur = pre.next; // 2
    let Cur_next;
    for(let i=0;i<n-m;i++){
        Cur_next = cur.next; // 暂存旧的下个节点,图中是5
        cur.next = Cur_next.next; // 2指向4【5的下个节点】
        Cur_next.next = pre.next; // 5指向2
        pre.next = Cur_next; // 7指向5
    }
    return dummyNode.next;
}
复杂度分析:

时间复杂度:O(N) 其中 N是链表总节点数。最多只遍历了链表一次,就完成了反转 空间复杂度O(1) 仅使用到常数个变量