小言_互联网的博客

链表基础题大全(三):奇偶链表和旋转链表

367人阅读  评论(0)

(尊重劳动成果,转载请注明出处:https://yangwenqiang.blog.csdn.net/article/details/105692949冷血之心的博客)

这段时间完成了职业生涯第一次跳槽,对算法题目有了一个更深的认识和理解,这里将链表常见的面试题目以及解法补充完善。

链表基础题大全(一)

链表基础题大全(二)

链表基础题大全(三):奇偶链表和旋转链表

链表基础题大全(四):单链表相加 & 复制带随机指针的链表 &判断回文链表

在前面两个小节的介绍中,我们主要介绍了基础的链表题目,主要是利用了双指针的思想。本篇博文,我们来看两道经典的题目:奇偶链表和旋转链表

奇偶链表

给定一个单链表,把所有的奇数节点和偶数节点分别排在一起。请注意,这里的奇数节点和偶数节点指的是节点编号的奇偶性,而不是节点的值的奇偶性。

请尝试使用原地算法完成。你的算法的空间复杂度应为 O(1),时间复杂度应为 O(nodes),nodes 为节点总数。

示例 1:
输入:1->2->3->4->5->NULL
输出:1->3->5->2->4->NULL

示例 2:
输入:2->1->3->5->6->4->7->NULL
输出:2->3->6->7->1->5->4->NULL

说明:

  • 应当保持奇数节点和偶数节点的相对顺序。
  • 链表的第一个节点视为奇数节点,第二个节点视为偶数节点,以此类推。

思路:
还算比较清晰吧,我们使用一个while循环遍历一遍链表,然后分别将奇数节点和偶数节点串起来,完事儿~

/**
* Definition for singly-linked list.
* public class ListNode {
*     int val;
*     ListNode next;
*     ListNode(int x) { val = x; }
* }
*/
class Solution {
    public ListNode oddEvenList(ListNode head) {
        if(head==null||head.next==null)
            return head;
        
         //保存头节点
        ListNode dummyHead = head;     
        ListNode node = head.next;
        //保存第一个偶数节点
        ListNode nextNode = head.next;
        while (node != null && node.next != null) {
            //依次将奇数节点链接起来
            head.next = head.next.next;
            head = head.next;
            //依次将偶数节点链接起来
            node.next = node.next.next;
            node = node.next;
        }
        //将第一个偶数节点链接到最后一个奇数节点的后面
        head.next = nextNode;
        return dummyHead;
    }
}

旋转链表

给定一个链表,旋转链表,将链表每个节点向右移动 k 个位置,其中 k 是非负数。

示例 1:
输入:1->2->3->4->5->NULL, k = 2
输出:4->5->1->2->3->NULL

解释:
向右旋转 1 步:5->1->2->3->4->NULL
向右旋转 2 步:4->5->1->2->3->NULL

示例 2:
输入:0->1->2->NULL, k = 4
输出:2->0->1->NULL

解释:
向右旋转 1 步:2->0->1->NULL
向右旋转 2 步:1->2->0->NULL
向右旋转 3 步:0->1->2->NULL
向右旋转 4 步:2->0->1->NULL

思路:

  • 根据题意,既然是旋转链表,有一种情况是旋转之后是其本身,这里需要特殊判断。
  • 然后我们需要做的就是通过双指针将链表分为前后两个部分,找到最终结果中的最后一个节点,也就是前半部分的最后一个节点;
  • 然后再找到后半部分的最后一个节点,将后半部分最后一个节点指向head节点
  • 然后就拼接完成啦~
/**
* Definition for singly-linked list.
* public class ListNode {
*     int val;
*     ListNode next;
*     ListNode(int x) { val = x; }
* }
*/
class Solution {
    public ListNode rotateRight(ListNode head, int k) {
        if(head==null||k<=0)
            return head;
        
        int step = k%getDepth(head);
        // 这块表示旋转之后还是本身
        if(step==0)
            return head;
        
        ListNode left = head;
        ListNode right = head;
        
        while(step>0){
            right = right.next;
            step--;
        }
        // 同时出发
        while(right.next!=null){
            left = left.next;
            right = right.next;
        }
        // 这个时候,left就是旋转之后的最后一个节点
        ListNode reHead = left.next;
        left.next=null;
        
        // 找到后半部分的最后一个节点
        ListNode reCur = reHead;
        while(reCur.next!=null){
            reCur = reCur.next;
        }
        // 将后半部分最后一个节点指向head节点
        reCur.next = head;
        
        // 拼接完成
        return reHead;
            
        
    }
    
    private int getDepth(ListNode head){
        int count = 0;
        while(head!=null){
            count++;
            head = head.next;
        }
        return count;
    }

总结:

奇偶链表和旋转链表也是常见的高频单链表题目,主要考察对于指针的操作(奇偶链表)以及双指针的使用(旋转链表),希望大家可以有效掌握与理解,看不懂的可以在纸上自己举个例子哈。

后续继续更新面试中常见的链表题目,欢迎大家关注~

注意啦,注意啦~

欢迎大家关注我的牛客专栏《Java开发岗面试题全解析》 ,点击图片查看详情。

Java开发岗高频面试题全解析,专栏共计32节,已经全部更新完毕。

专栏分9个模块来对Java岗位面试中的知识点进行解析,包括通用面试技能,Java基础,Java进阶,网络协议,常见框架以及算法,设计模式等。

专栏串点成面的解析每个面试题背后的技术原理,由浅入深,循序渐进,力争让大家掌握面试题目的背后的技术原理,摒弃背题模式的陋习。


如果对你有帮助,记得点赞哈,欢迎大家关注我的博客,关注公众号(文强的技术小屋),学习更多技术知识,一起遨游知识海洋~


转载:https://blog.csdn.net/qq_25827845/article/details/105692949
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场