算法-约瑟夫环问题

题目: 给定两个可能有环也可能无环的单链表,头结点 head1 和 head2。 请实现一个函数,如果两个链表相交,请返回相交的 第一个节点 。如果不相交,返回 null 【要求】 如果两个链表的长度之和为 N ,时间复杂度请达到 O(N) , 额外空间复杂度请达到 O(1) 。

使用容器定位

  • 思路一 (空间复杂度无法达到要求)使用容器完成约瑟夫环:

    比如无环链表: head->A->B->C->D->E->null 与 有环链表: head->A->B->C->D->B->E->null 可以使用 hash 表进行存储,当因为 hash 表中存储的元素都是唯一的,也就是说当我们在遍历链表的过程当中, 将元素置入 hash 表当中,如果链表遍历但最后一个 null 都没有出现重复的元素,则表示该链表不存在环。 如果在遍历的过程当中,一但出现重复的元素,则表示该链表已经形成了一个环。

kotlin 复制代码
    /**
     * 利用容器实现环的查找
     *
     * @param elements
     * @param <E>
     * @return
     */
    public static <E> E vesselScreen(LinkedList<E> elements) {
        HashSet<E> screen = new HashSet<E>();
        for (int i = 0; i < elements.getSize(); i++) {
            E data = elements.get(i);
            if (screen.contains(data))
                return data;
            screen.add(data);
        }
        return null;
    }

通过快慢指针定位

  • 思路二 (空间复杂度 O(1))使用快慢指针:

    通过快慢两个指针的移动,完成对该链表的遍历。如果慢指针最终指向空,则表示该链表是不存在环的,如果慢指针最终追上了快指针,则表示必定有环,因为当没有环的时候,本身快指针就比慢指针走的快,是不可能相遇的。

虽然是相遇,但是却无法定位到入环节点。当两个指针相遇的时候,快指针回到开头节点,快指针走一步,而慢指针走两步,而当快慢指针再次相遇的时候,便是入环的节点。

附录-代码

  • 节点元素

    kotlin 复制代码
    package com.peppa.common;
    ​
    /**
     * 自定义对的节点元素
     * @param <T>
     */
    public class Node<T> {
        T data;
        Node<T> next;
        public Node(T data){
            this.data=data;
            this.next=null;
        }
    }
  • 链表结构

    ini 复制代码
    package com.peppa.common;
    ​
    /**
     * 自定义链表结构
     */
    public class LinkedList<T> {
        private Node<T> head; // 头结点
        private int length; // 链表长度
    ​
        // 添加元素到尾巴节点
        public void append(Node<T> data) {
            if (head == null) {
                head = data;
                length = 1;
                return;
            }
            Node<T> current = head;
            while (current.next != null) { // 定位到最后的一个元素
                current = current.next;
            }
            current.next = data;// 追加到尾部
            length++;
        }
    ​
        //打印链表元素
        public void printList() {
            Node<T> current = head;
            int coutn = 0;
            while (current != null && coutn < length) {
                System.out.print(current.data + " ");
                current = current.next;
                coutn++;
            }
            System.out.println();
        }
    ​
        //根据元素下标获取元素数据
        public T get(int index) {
            Node<T> current = head;
            if (index > length << 1) {
                return current.data;
            }
            for (int i = 0; i < index; i++) {
                current = current.next;
            }
            return current.data;
        }
    ​
        public int getSize() {
            return length;
        }
    ​
    }
  • main

    ini 复制代码
    /**
         * 运行程序
         *
         * @param args
         */
        public static void main(String[] args) {
            LinkedList<Integer> linkedList = new LinkedList();
            Node<Integer> integerNode_1 = new Node<Integer>(1);
            Node<Integer> integerNode_2 = new Node<Integer>(2);
            Node<Integer> integerNode_3 = new Node<Integer>(3);
            Node<Integer> integerNode_4 = new Node<Integer>(4);
            Node<Integer> integerNode_5 = new Node<Integer>(5);
            Node<Integer> integerNode_6 = new Node<Integer>(6);
            Node<Integer> integerNode_7 = new Node<Integer>(7);
            linkedList.append(integerNode_1);
            linkedList.append(integerNode_2);
            linkedList.append(integerNode_3);
            linkedList.append(integerNode_4);
            linkedList.append(integerNode_5);
            linkedList.append(integerNode_6);
            linkedList.append(integerNode_7);
            linkedList.append(integerNode_3);
            linkedList.printList();
    ​
            Integer data = vesselScreen(linkedList);
            if (data != null)
                System.out.println("有环-相交元素为: " + data);
            else
                System.out.println("无环-无相交元素");
        }

    算法文件地址

    约瑟夫环

相关推荐
半盏茶香2 小时前
C语言勘破之路-最终篇 —— 预处理(下)
c语言·开发语言·c++·算法
pianmian17 小时前
贪心算法.
算法·贪心算法
chenziang18 小时前
leetcode hot 100 二叉搜索
数据结构·算法·leetcode
single5949 小时前
【c++笔试强训】(第四十五篇)
java·开发语言·数据结构·c++·算法
呆头鹅AI工作室10 小时前
基于特征工程(pca分析)、小波去噪以及数据增强,同时采用基于注意力机制的BiLSTM、随机森林、ARIMA模型进行序列数据预测
人工智能·深度学习·神经网络·算法·随机森林·回归
一勺汤10 小时前
YOLO11改进-注意力-引入自调制特征聚合模块SMFA
人工智能·深度学习·算法·yolo·目标检测·计算机视觉·目标跟踪
每天写点bug11 小时前
【golang】map遍历注意事项
开发语言·算法·golang
程序员JerrySUN11 小时前
BitBake 执行流程深度解析:从理论到实践
linux·开发语言·嵌入式硬件·算法·架构
王老师青少年编程12 小时前
gesp(二级)(16)洛谷:B4037:[GESP202409 二级] 小杨的 N 字矩阵
数据结构·c++·算法·gesp·csp·信奥赛
robin_suli12 小时前
动态规划子序列问题系列一>等差序列划分II
算法·动态规划