234. 回文链表 Palindrome Linked List 143. 重排链表Reorder List 92. Reverse Linked List II【 反转链表 2】

71 篇文章 0 订阅

234 回文链表 Palindrome Linked List

问题
请判断一个链表是否为回文链表:正看和倒着看一样
例子
在这里插入图片描述
思路
[]是
[1]是
[1,2,1]是
[1,2,2,1]是

  • 先判断[]和[1],都返回true
  • 方法1 O(N) 空间复杂度O(n)

先遍历链表,保存值到数组
然后按判断字符串回文方式:前后两个指针,向中间走
确保i<j:奇数个,跳出循环时:i==j,偶数个跳出循环时:i>j

  • 方法2 O(N) 空间复杂度O(1)
    在这里插入图片描述

先找到中间结点,然后反转中间结点后面到结尾的所有结点。slow=head,fast=head。
//最终fast为null:1+2m=n+1==n=2m slow=1+m为4个的第3个
//最终fast是最后一个节点:1+2m=n slow=1+m为5个的第3个
反转后面的n/2个节点,此时后面反转的节点为<=前面链表的节点数量
比较两个链表

代码

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def isPalindrome(self, head: ListNode) -> bool:
        if head is None or head.next is None: return True
        arr=[]
        while head :
            arr.append(head.val)
            head=head.next

        i=0
        j=len(arr)-1
        while i<j:
            if arr[i]!=arr[j]:
                return False
            i+=1
            j-=1
        return True
#方法2

class Solution:
    def isPalindrome(self, head: ListNode) -> bool:
        if head is None or head.next is None: return True
        old=head
        slow=head
        fast=head.next
        hhead=ListNode(-1)
        while fast and fast.next:
            fast=fast.next.next
            slow=slow.next
        #此时:为奇数个时slow为中间结点,为偶数个时,为前半段的最后一个,.next取后半段
        
        slow=slow.next
        #将后半段进行反转
        while slow:
            t=slow.next
            slow.next=hhead.next
            hhead.next=slow
            
            slow=t
        new = hhead.next 
        #比较前半段和后半段(为奇数个时,前半段长度-后半段长度=1)
        while new:#因为new是后半段,当为偶数个时,和前半段一样长,当为奇数个时,比前半段少一个中间结点
            if new.val!=old.val:
                return False
            new = new.next
            old=old.next
            
        return True
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public boolean isPalindrome(ListNode head) {
        if (head==null || head.next==null) return true;
        
        List<Integer> list = new ArrayList<>();
        while (head!=null) {
            list.add(head.val);
            head=head.next;
        }
        
        int i=0,j=list.size()-1;
        while (i<j) {

            if(!list.get(i).equals(list.get(j))) return false;
         
            i++;
            j--;
        }
        
        return true;
    }
}
//方法2
class Solution {
    public boolean isPalindrome(ListNode head) {
        ListNode slow=head,fast=head,h1=head;
        //找到中间节点。由于slow和fast第一次都走了一步。
        //最终fast为null:1+2m=n+1==n=2m slow=1+m为4个的第3个
        //最终fast是最后一个节点:1+2m=n slow=1+m为5个的第3个
        while(fast!=null && fast.next!=null)
        {
            fast = fast.next.next;
            slow = slow.next;
        }
        
        //将后面len/2部分反转
        ListNode h2 = new ListNode(0);
        while(slow!=null){
            ListNode temp = slow.next;
            slow.next = h2.next;
            h2.next = slow;
            slow = temp;
        }
        //h2此时为去掉头结点的反转链表
        h2 = h2.next;
        
        while(h2!=null){
            
            if(h1.val!=h2.val) return false;
            
            h1 = h1.next;
            h2 = h2.next;
            
        }

        return true;
        
    }
}

143. 重排链表Reorder List

问题

在这里插入图片描述

例子

在这里插入图片描述
思路

先找到中间结点(偏后),然后反转中间结点后面到结尾的所有结点。slow=head,fast=head。
//最终fast为null:1+2m=n+1==n=2m slow=1+m为4个的第3个
//最终fast是最后一个节点:1+2m=n slow=1+m为5个的第3个
反转后面的n/2个节点,此时后面反转的节点为<=前面链表的节点数量

在这里插入图片描述
得到两个链表:h1 数目为n/2上取整,h2 数目n/2下取整,然后依次拼接,知道h2链表到达之前找到的中间节点(偏厚)slow【或者说h2到最后一个即.next==null】,拼接完成
在这里插入图片描述
在这里插入图片描述

代码

class Solution {
    public void reorderList(ListNode head) {
        if(head==null || head.next==null) return ;
        ListNode fast=head,slow=head,h1=head;
        
        while(fast!=null && fast.next!=null){
            fast = fast.next.next;
            slow = slow.next;
        }
        
        ListNode mid = slow;
        ListNode h2 = new ListNode(0);
        while(slow!=null){
            ListNode t = slow.next;
            slow.next = h2.next;
            h2.next = slow;
            slow = t;
        }
        
        h2 = h2.next;
        
        //然后依次拼接,知道h2链表到达之前找到的中间节点(偏厚)slow【或者说h2到最后一个即.next==null】,拼接完成
        while(h2!=mid){//h2.next!=null
            ListNode t1 = h1.next,t2=h2.next;
            h2.next = h1.next;
            h1.next = h2;
            h1=t1;
            h2=t2;
        }
        return ;
        
        
    }
}

92. Reverse Linked List II【 反转链表 2】

描述

Reverse a linked list from position m to n. Do it in one-pass
1 ≤ m ≤ n ≤ length of list

反转从位置 m 到 n 的链表。请使用一趟扫描完成反转。
1 ≤ m ≤ n ≤ 链表长度

例子
在这里插入图片描述
思路
在这里插入图片描述
l-1不一定存在,所以先知道一个头结点h.next = head
在这里插入图片描述

在这里插入图片描述
关键点:

  • m-1_node是否存在影响很大,因为m-1_node.next=反转链表,而n+1_node是否存在无影响

  • 2:遍历链表时,无论怎么样,cur都要变为cur.next,结合遇到反转的结点要保存下一个结点,所以直接:xia=cur.next cur=xia
    在这里插入图片描述
    答案

  • java

//先造一个头结点,遍历时反转(第二种头插法)
class Solution {
    public ListNode reverseBetween(ListNode head, int m, int n) {
        
            //需要第l-1,l,r,r+1四个节点信息,其中后三个一定存在(r+1节点可能为null),为保证l-1一定存在加上头结点,此时第x个,变成下标为x
        ListNode h = new ListNode(0);
        h.next = head;
        ListNode pre = h;

        
        //pre为下标l-1,到它一共有l个节点,除去第一个,还有l-1个,即需要走l-1步
        for(int i=0; i<left-1; i++)
            pre = pre.next;
        
        ListNode lnode = pre.next;
        //挨个删除left后面的节点,并插到pre后面。共删除:right-left+1 - 1个。
        //反转部分共有:right-left+1个,由于left节点天然已经跟pre插入 
        for(int i=0; i<right-left; i++)
        {
            ListNode remove = lnode.next;
            lnode.next = remove.next;

            remove.next = pre.next;
            pre.next = remove;
        }

        return h.next;
    }
}
//插个头结点,然后找到l-1,l,r,r+1,将l~r部分反转,然后接上。
class Solution {
    public ListNode reverseBetween(ListNode head, int left, int right) {

        
        ListNode h = new ListNode(0);
        h.next = head;
        ListNode hh = h;

        int i=0;
        ListNode pre = null,lnode=null,rnode=null,back=null;
        while(h!=null){
            if(i==left-1) pre=h;
            if(i==left) lnode = h;
            if(i==right) rnode = h;
            if(i==right+1) {
                back = h;
                break;
            }
            i++;
            h = h.next;
            
        }
        rnode.next = null;
        pre.next = reverse(lnode);
        lnode.next = back;
        
        return hh.next;
        
        
    }
    
    public ListNode reverse(ListNode head){
        if(head==null || head.next==null) return head;
        ListNode next = head.next;
        ListNode h = reverse(next);
        head.next = null;
        next.next = head;
        
        return h;
    }
}
  • python
    def reverseBetween(self, head: ListNode, m: int, n: int) -> ListNode:
        cur = head
        h = ListNode(0)
        m_node, m_less_node = None, None
        now = 1
        while now <= n:
            xia = cur.next
            if now >= m - 1:
                if now == m - 1:
                    m_less_node = cur
                else:  # >=m
                    if now == m:
                        m_node = cur
                    # >=m时
                    cur.next = h.next
                    h.next = cur

            cur = xia
            now += 1


        m_node.next = cur  # 为第n+1个
        if m_less_node:
            m_less_node.next = h.next
            return head
        else:
            return h.next
  • c++
public:
    ListNode* reverseBetween(ListNode* head, int m, int n) {
        ListNode* cur=head;//遍历链表
        ListNode* h=new ListNode(0);//反转链表块的头结点
     
        ListNode* m_less_node = NULL,*m_node=NULL,*xia=NULL;
        int now = 1;
        while(now <=n)
        {
            xia = cur->next;
            if (now>=m-1)
            {
                if (now==m-1)
                    m_less_node = cur;
                else
                {//包含<=n
                    if (now==m)
                        m_node = cur;
                    
                    cur->next=h->next;
                    h->next=cur;  
                }
            }
            cur=xia;
            now ++;
        }
        
        m_node->next = cur;//cur 为n+1结点
        if (m_less_node)
        {
            m_less_node->next = h->next;//n结点
            return head;
        }
        else
            return h->next;
        
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值