链表常见题型

环形链表插值练习题

有一个整数val,如何在节点值有序的环形链表中插入一个节点值为val的节点,并且保证这个环形单链表依然有序。
给定链表的信息,及元素的值A及对应的nxt指向的元素编号同时给定val,请构造出这个环形链表,并插入该值。
测试样例:
[1,3,4,5,7],[1,2,3,4,0],2
返回:{1,2,3,4,5,7}

分析:
一共有三种情况
1、如果原链表为空
2、如果链表不为空
3、如果p和c转一圈都没有发现应该插入的位置,此时node应该插入头节点的前面

import java.util.*;


class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}
public class InsertValue {
    public ListNode insert(int[] A, int[] nxt, int val) {

        if (A == null || A.length == 0){
            ListNode node = new ListNode(val);
            return node;
        }
        ListNode head = new ListNode(A[0]);
        // 构建有序链表(并非环形,因为不能题目不让返回环形)
        ListNode headTemp = head;
        for (int i = 0; i < A.length-1; i++){
            ListNode temp = new ListNode(A[nxt[i]]);
            headTemp.next = temp;
            headTemp = temp;
        }
        // 如果值小于链表头部值,则插入头部,且返回node链表
        if (val < head.val){
            ListNode node = new ListNode(val);
            node.next = head;
            return node;
        }

        // 循环遍历,寻找合适的位置插入
        ListNode pre = head;
        ListNode cur = pre.next;
        while (cur != null){
            if (val >= pre.val && val <= cur.val){
                break;
            }
            pre = cur;
            cur = cur.next;
        }
        // 要么是找到了合适的位置(break出来),要么是val都大于链表值,在最后位置插入
        ListNode node = new ListNode(val);
        node.next = cur;
        pre.next = node;

        return head;

    }
}

访问单个节点的删除练习题

实现一个算法,删除单向链表中间的某个结点,假定你只能访问该结点。
给定带删除的节点,请执行删除操作,若该节点为尾节点,返回false,否则返回true

分析:
1、下一个节点指向删除的节点,然后删除下一个节点

import java.util.*;


class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}
public class Remove {
    public boolean removeNode(ListNode pNode) {
        // 空节节不能删除
        if (pNode == null){
            return false;
        }
        ListNode next = pNode.next;
        // 空节点不能赋值给节点
        if (next == null){
            return false;
        }
        pNode.val = next.val;
        pNode.next = next.next;
        return true;

    }
}

链表的分化练习题

对于一个链表,我们需要用一个特定阈值完成对它的分化,使得小于等于这个值的结点移到前面,大于该值的结点在后面,同时保证两类结点内部的位置关系不变。
给定一个链表的头结点head,同时给定阈值val,请返回一个链表,使小于等于它的结点在前,大于等于它的在后,保证结点值不重复。
测试样例:
{1,4,2,5},3
返回结果:
{1,2,4,5}
分析:
1、建立两个链表:小于等于val链表,大于val链表

import java.util.*;

class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}
public class Divide {
    public ListNode listDivide(ListNode head, int val) {
        if (head == null || head.next == null){
            return head;
        }
        // 当前节点
        ListNode curNode = head, temp = null;
        // 小于val的链表与尾节点
        ListNode smallerHead = null, smallerTail = null;
        // 与大于val的链表与尾节点
        ListNode biggerHead = null, biggerTail = null;
        while (curNode != null){
            // 取出第一个节点
            temp = curNode;
            curNode = curNode.next;

            // 避免其它链表连接后成为闭环
            temp.next = null;
            int value = temp.val;


            if (value <= val){
                // 如果是第一个,则附头
                if (smallerHead == null){
                    smallerHead = temp;
                }
                // 如果不是第一个,则尾部添加
                else{
                    smallerTail.next = temp;
                }
                // 尾部指向最后一个
                smallerTail = temp;
            }
            else {
                 // 如果是第一个,则附头
                if (biggerHead == null){
                    biggerHead = temp;
                }
                // 如果不是第一个,则尾部添加
                else{
                    biggerTail.next = temp;
                }
                // 尾部指向最后一个
                biggerTail = temp;
            }
        }
        // 如果小的链表没值,则返回大的链表
        if (smallerHead == null){
            return biggerHead;
        }
        // 如果大的链表没值,则返回小的链表
        if (biggerHead == null){
            return smallerHead;
        }
        // 小链表与大链表连接
        smallerTail.next = biggerHead;
        return smallerHead;

    }
}

打印两个链表的公共值练习题

现有两个升序链表,且链表中均无重复元素。请设计一个高效的算法,打印两个链表的公共值部分。
给定两个链表的头指针headA和headB,请返回一个vector,元素为两个链表的公共部分。请保证返回数组的升序。两个链表的元素个数均小于等于500。保证一定有公共值
测试样例: {1,2,3,4,5,6,7},{2,4,6,8,10}
返回:[2.4.6]

分析:
1、两数比较,小的自己+1,等于的装进数组,然后都+1

import java.util.*;

class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}
public class Common {
    public int[] findCommonParts(ListNode headA, ListNode headB) {
        List<Integer> list = new ArrayList<>();
        while (headA != null && headB != null){
            if (headA.val < headB.val){
                headA = headA.next;
            }
            else if (headA.val > headB.val){
                headB = headB.next;
            }
            else{
                list.add(headA.val);
                headA = headA.next;
                headB = headB.next;
            }
        }
        int[] a = new int[list.size()];
        for (int i = 0; i < list.size(); i++)
        {
            a[i] = list.get(i);
        }
        return a;

    }
}

链表的k逆序练习题

有一个单链表,请设计一个算法,使得每K个节点之间逆序,如果最后不够K个节点一组,则不调整最后几个节点。例如链表1->2->3->4->5->6->7->8->null,K=3这个例子。调整后为,3->2->1->6->5->4->7->8->null。因为K==3,所以每三个节点之间逆序,但其中的7,8不调整,因为只有两个节点不够一组。 给定一个单链表的头指针head,同时给定K值,返回逆序后的链表的头指针。

分析:
1、使用栈存储3个数,出栈就是倒序啦。里边有许多的细节需要画图处理的

import java.util.*;

class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}
public class KInverse {
    public ListNode inverse(ListNode head, int k) {
        if (k < 2){
            return head;
        }
        Stack<ListNode> stack = new Stack<>();
        ListNode newHead = head, cur = head;
        // 上一个链表的末端,下一个链表的开始
        ListNode preEnd = null, nextStart = null;
        while (cur != null){
            nextStart = cur.next;
            stack.push(cur);
            if (stack.size() == k){
                preEnd = reload(stack, preEnd, nextStart);
                // 因为逆序了,所以头结点需要改变(就一次)
                if (newHead == head){
                    newHead = cur;
                }
            }
            cur = nextStart;
        }
        return newHead;
    }
    public ListNode reload(Stack<ListNode> stack, ListNode preEnd, ListNode nextStart){
        ListNode cur = stack.pop();
        // 如果不等于null,则上一个末端(preEnd)直接连接当前(cur)的节点
        if (preEnd != null){
            preEnd.next = cur;
        }
        ListNode next = null;
        while (!stack.isEmpty()){
            next = stack.pop();
            cur.next = next;
            cur = next;
        }
        // 三个节点中的最后一个节点与下一个链表(nextStart)连接
        cur.next = nextStart;
        // 返回当前链表的最后一个节点
        return cur;
    }
}

链表指定值清除练习题

现在有一个单链表。链表中每个节点保存一个整数,再给定一个值val,把所有等于val的节点删掉。
给定一个单链表的头结点head,同时给定一个值val,请返回清除后的链表的头结点,保证链表中有不等于该值的其它值。请保证其他元素的相对顺序。
测试样例:
{1,2,3,4,3,2,1},2
返回值:
{1,3,4,3,1}

分析:
1、遍历链表,一样的值则删除掉

import java.util.*;

class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}
public class ClearValue {
    public ListNode clear(ListNode head, int val) {
        // 避免头部为一样值
        while (head != null){
            if (head.val != val)
                break;
            head = head.next;
        }
        ListNode pre = head;
        ListNode cur = head;
        // 遍历链表,一样的值则删除
        while (cur != null){
            if (cur.val == val){
                pre.next = cur.next;
            }
            else {
                pre = cur;
            }
            cur = cur.next;
        }
        return head;
    }
}

链表的回文结构练习题

请编写一个函数,检查链表是否为回文。 给定一个链表ListNode* pHead,请返回一个bool,代表链表是否为回文。
测试样例:
{1,2,3,2,1}
返回:true
{1,2,3,2,3}

分析:
回文:是否对称
1、将数据全入栈,出栈的时候与链表一一比较,都相等则回文。。

import java.util.*;


class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}
public class Palindrome {
    public boolean isPalindrome(ListNode pHead) {
        if (pHead == null){
            return false;
        }
        Stack<ListNode> stack = new Stack<>();
        // 将节点都放到栈里
        ListNode cur = pHead;
        while (cur != null){
            stack.push(cur);
            cur = cur.next;
        }
        // 出栈,看是否全都相等
        ListNode temp = null;
        cur = pHead;
        while (!stack.isEmpty()){
            temp = stack.pop();
            if (temp.val != cur.val){
                return false;
            }
            else {
                cur = cur.next;
            }
        }
        return true;
    }
}

链表判环练习题

如何判断一个单链表是否有环?有环的话返回进入环的第一个节点的值,无环的话返回-1。如果链表的长度为N,请做到时间复杂度O(N),额外空间复杂度O(1)。
给定一个单链表的头结点head(注意另一个参数adjust为加密后的数据调整参数,方便数据设置,与本题求解无关),请返回所求值。

import java.util.*;


class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}
public class ChkLoop {
    public int chkLoop(ListNode head, int adjust) {
        ListNode fast = head;
        ListNode slow = head;
        boolean circle = false;
        while (fast != null && fast.next != null){
            fast = fast.next.next;
            slow = slow.next;
            // 当相等时说明是闭环;
            if (fast == slow){
                circle = true;
                break;
            }
        }
        if (circle == false){
            return -1;
        }
        // fast再从头来开始,当它们再次相遇说明是入口点;
        fast = head;
        while(fast != slow){
            fast = fast.next;
            slow = slow.next;
        }
        return fast.val;

    }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
循环链表是解决约瑟夫问题的一种常见方法。下面是一个使用Java循环链表解决约瑟夫问题的示例: ```java class Node { int data; Node next; public Node(int data) { this.data = data; } } class CircularLinkedList { private Node head; private Node tail; public void add(int data) { Node newNode = new Node(data); if (head == null) { head = newNode; tail = newNode; tail.next = head; } else { tail.next = newNode; tail = newNode; tail.next = head; } } public void remove(Node node) { if (head == null) { return; } if (head == node) { head = head.next; tail.next = head; } else { Node current = head; while (current.next != node) { current = current.next; } current.next = node.next; if (node == tail) { tail = current; tail.next = head; } } } public void josephus(int k) { Node current = head; while (current.next != current) { for (int i = 1; i < k; i++) { current = current.next; } System.out.print(current.data + " "); remove(current); current = current.next; } System.out.println(current.data); } } public class Main { public static void main(String[] args) { CircularLinkedList list = new CircularLinkedList(); int n = 7; // 总人数 int k = 3; // 报数为3的人出列 for (int i = 1; i <= n; i++) { list.add(i); } System.out.println("出列顺序:"); list.josephus(k); } } ``` 这段代码中,我们首先定义了一个`Node`类来表示循环链表的节点,然后定义了`CircularLinkedList`类来实现循环链表的操作。在`josephus`方法中,我们使用循环链表模拟约瑟夫问题的解决过程,每次找到第k个节点并移除,直到只剩下一个节点为止。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值