链表(2)——中等难度

链表—中等难度(java实现)

链表中环的入口节点

题目描述
对于一个给定的链表,返回环的入口节点,如果没有环,返回null
拓展:
你能给出不利用额外空间的解法么?

牛客题解图片
(图源牛客LPL006题解)

/**
 * Definition for singly-linked list.
 * class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public ListNode detectCycle(ListNode head) {
        ListNode fast = head;
        ListNode slow = head;
        //设在进入环前路程为a,二指针在距环起点为b位置相遇,环总长(b+c)
        //即慢指针行 a+b , 快指针行a+b+n(b+c)
        //快指针速度为慢指针2倍,则 2*(a+b)=a+b+n*(b+c)
        //推出 a = (n-1)(b+c) + c
        //此时将速度相同的两个指针分别放在开头和环相遇位置,二者相遇在环起点  
        while(fast != null && fast.next != null){
            fast = fast.next.next;
            slow = slow.next;
            if(fast == slow){
                ListNode tmp = head;
                while(tmp != slow){
                    tmp = tmp.next;
                    slow = slow.next;
                }
                return slow;
            }
               
        }
        
        return null;
    }
}

删除链表的倒数第n个节点

题目描述
给定一个链表,删除链表的倒数第n个节点并返回链表的头指针
例如,
给出的链表为:1->2->3->4->5, n= 2.
删除了链表的倒数第n个节点之后,链表变为1->2->3->5.

备注:
题目保证n一定是有效的
请给出请给出时间复杂度为\ O(n) O(n)的算法

题目已知给出的n一定是有效的,所以无需再考虑n小于0或者大于链表长度的情况

import java.util.*;

/*
 * public class ListNode {
 *   int val;
 *   ListNode next = null;
 * }
 */

public class Solution {
    /**
     * 
     * @param head ListNode类 
     * @param n int整型 
     * @return ListNode类
     */
    public ListNode removeNthFromEnd (ListNode head, int n) {
        // write code here
        
        ListNode fast = head;
        ListNode slow = head;
        
        for(int i = 0; i < n; i++)
            fast = fast.next;
        
        //若n等于链表的长度,则直接返回去掉头结点的链表
        if(fast == null)
            return head.next;
        
        while(fast.next != null){
            fast = fast.next;
            slow = slow.next;
        }
        //1 2 3 4 5 6 7   
        slow.next = slow.next.next;
        
        return head;
        
    }
}

删除有序链表中重复出现的元素

题目描述
给出一个升序排序的链表,删除链表中的所有重复出现的元素,只保留原链表中只出现一次的元素。
例如:
给出的链表为1→2→3→3→4→4→5, 返回1→2→5.
给出的链表为1→1→1→2→3, 返回2→3.

import java.util.*;

/*
 * public class ListNode {
 *   int val;
 *   ListNode next = null;
 * }
 */

public class Solution {
    /**
     * 
     * @param head ListNode类 
     * @return ListNode类
     */
    public ListNode deleteDuplicates (ListNode head) {
        // write code here
        
        ListNode res = new ListNode(0);
        res.next = head;
        
        ListNode pre = res;
        ListNode cur = head;
       
        
        while(cur != null && cur.next != null){
            if(cur.val != cur.next.val)
                pre = cur;
            else{
                while(cur.next != null && cur.val == cur.next.val)
                    cur = cur.next;
                pre.next = cur.next;
            }
            
            cur = cur.next;
        
        }
        
        return res.next;
    }
}

链表的奇偶重排

题目描述
给定一个单链表,请设定一个函数,讲链表的奇数位节点和偶数位节点分别放在一起,重排后输出。
注意是节点的编号而非节点的数值。

示例1
输入:{1,2,3,4,5,6}
返回值:{1,3,5,2,4,6}

示例2
输入:{1,4,6,3,7}
返回值:{1,6,7,4,3}

说明:奇数节点有1,6,7,偶数节点有4,3。重排后为1,6,7,4,3

备注:链表长度不大于200000。每个数范围均在int内。

import java.util.*;

/*
 * public class ListNode {
 *   int val;
 *   ListNode next = null;
 * }
 */

public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     * 
     * @param head ListNode类 
     * @return ListNode类
     */
    public ListNode oddEvenList (ListNode head) {
        // write code here
       if(head == null || head.next == null)
           return head;
        ListNode evenhead = head.next;
        ListNode odd = head;
        ListNode even = head.next;
        
        int i = 1;
        
        while(even != null && even.next != null){
            odd.next = even.next;
            odd = odd.next;
            even.next = odd.next;
            even = even.next;
        }
        //奇数链与偶数链相连
        odd.next = evenhead;
        return head;
       
    }
}

划分链表

题目描述
给出一个链表和一个值 ,以 为参照将链表划分成两部分,使所有小于 的节点都位于大于或等于 的节点之前。
两个部分之内的节点之间要保持的原始相对顺序。
例如:
给出1→4→3→2→5→2 和x=3,
返回 1→2→2→4→3→5.

示例1
输入:{1,4,3,2,5,2},3
返回值:{1,2,2,4,3,5}

import java.util.*;

/*
 * public class ListNode {
 *   int val;
 *   ListNode next = null;
 * }
 */

public class Solution {
    /**
     * 
     * @param head ListNode类 
     * @param x int整型 
     * @return ListNode类
     */
    public ListNode partition (ListNode head, int x) {
        // write code here
        if(head == null)
            return null;
        ListNode res1 = new ListNode(0);
        ListNode res2 = new ListNode(0);
        ListNode left = res1;
        ListNode right = res2;
        
        while(head != null){
            if(head.val < x){
                 left.next = head;
                left = left.next;
            }
            else{
                right.next = head;
                right = right.next;
            }
            
            head =head.next;
        }
        
        right.next = null;
        left.next = res2.next;
        return res1.next;
      
    }
}

重排链表

题目描述
将给定的单链表 L: L0→L1→…→Ln-1→Ln

重新排序为:L0→Ln →L1→Ln-1→L2→Ln-2→…

要求使用原地算法,不能改变节点内部的值,需要对实际的节点进行交换。
例如:
对于给定的单链表{10,20,30,40},将其重新排序为{10,40,20,30}.

/**
 * Definition for singly-linked list.
 * class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public void reorderList(ListNode head) {
        //要求使用原地算法,不能改变节点内部的值
        //反转后半部分链表
        
        if(head == null || head.next == null)
            return;
        
        //1、快慢指针找中点
        ListNode fast = head;
        ListNode slow = head;
        
        while(fast.next != null && fast.next.next != null){
            fast = fast.next.next;
            slow = slow.next;
        }
        
        ListNode cur = slow.next;
        slow.next = null;       //拆分链表
        ListNode pre = null;    //后半部分链表的尾
        
        while(cur != null){
            ListNode nex = cur.next;
            cur.next = pre;
            pre = cur;
            cur = nex;
        }
        cur = pre;     //注意:在走完循环之后pre指向头结点,cur指向null
        
        //合并两个链表
        
        ListNode res = head;
        while(res != null && cur != null){
            ListNode ftmp = res.next;
            ListNode ctmp = cur.next;
            
            //1 2 3 4 5
            //9 8 7 6
            res.next = cur;
            res = ftmp;
            cur.next = res;
            cur = ctmp;
        }
    }
}

两个链表生成相加链表

题目描述
假设链表中每一个节点的值都在 0 - 9 之间,那么链表整体就可以代表一个整数。
给定两个这种链表,请生成代表两个整数相加值的结果链表。
例如:链表 1 为 9->3->7,链表 2 为 6->3,最后生成新的结果链表为 1->0->0->0。

示例1
输入:[9,3,7],[6,3]
返回值:{1,0,0,0}
备注:
1 ≤ n,m ≤ 10^6
0 ≤ ai,bi ≤ 9

import java.util.*;

/*
 * public class ListNode {
 *   int val;
 *   ListNode next = null;
 * }
 */

public class Solution {
    /**
     * 
     * @param head1 ListNode类 
     * @param head2 ListNode类 
     * @return ListNode类
     */
    public ListNode addInList (ListNode head1, ListNode head2) {
        // write code here
        if(head1 == null) return head2;
        if(head2 == null) return head1;
        
        //方法一利用栈
        //方法二反转链表
        
        Stack<Integer> s1 = new Stack<>();
        Stack<Integer> s2 = new Stack<>();
        
        while(head1 != null){
            s1.push(head1.val);
            head1 = head1.next;
        }
        
        while(head2 != null){
            s2.push(head2.val);
            head2 = head2.next;
        }
        
        
        ListNode pre = null;
        ListNode cur = null;
        
        int n1 = 0;
        int n2 = 0;
        int cu = 0;    //本位
        int cp = 0;    //进位
        while(!s1.isEmpty() || !s2.isEmpty()){
            n1 = s1.isEmpty() ? 0 : s1.pop();
            n2 = s2.isEmpty() ? 0 : s2.pop();
            
            cu = (cp + n1 + n2) % 10;
            cp = (cp + n1 + n2) / 10;
            
            pre = cur;
            cur = new ListNode(cu);
            cur.next = pre;      //注意最后链表的顺序
        }
        
        if(cp != 0){    //两表遍历完,还有进位
            pre = cur;
            cur = new ListNode(cp);
            cur.next = pre;
        }
        
        
        return cur;
      
        
        
        
    }
}

链表指定区间反转

题目描述
将一个链表 m 位置到 n 位置之间的区间反转,要求时间复杂度 O(n) ,空间复杂度 O(1) 。
例如:
给出的链表为1→2→3→4→5→NULL, m = 2,n = 4,
返回1→4→3→2→5→NULL.

注意:
给出的 满足以下条件:
链表长度1≤m≤n≤链表长度

示例1
输入:{1,2,3,4,5},2,4
返回值:{1,4,3,2,5}

import java.util.*;

/*
 * public class ListNode {
 *   int val;
 *   ListNode next = null;
 * }
 */

public class Solution {
    /**
     * 
     * @param head ListNode类 
     * @param m int整型 
     * @param n int整型 
     * @return ListNode类
     */
    public ListNode reverseBetween (ListNode head, int m, int n) {
        // write code here
        ListNode res = new ListNode(0);
        res.next = head;
       
        ListNode cur = head;
        ListNode pre = res;
      
        
        for(int i = 1; i < m; i++){
            pre = cur;
            cur = cur.next;
        }
            
        //1 2 3 4 5 6 7
        //1 3 2 4 5 6 7
        //1 4 3 2 5 6 7
        /*
        不妨拿出四本书,摞成一摞(自上而下为 A B C D),要让这四本书的位置完全颠倒过来(即自上而下为 D C B A):

盯住书A,每次操作把A下面的那本书放到最上面

初始位置:自上而下为 A B C B

第一次操作后:自上而下为 B A C D

第二次操作后:自上而下为 C B A D

第三次操作后:自上而下为 D C B A
        */
        for(int i = 0; i < n - m; i++){
           ListNode tmp = cur.next;
           cur.next = tmp.next;
           tmp.next  = pre.next;
            pre.next = tmp;
        }
        
        return res.next;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值