算法-约瑟夫环问题

题目: 给定两个可能有环也可能无环的单链表,头结点 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("无环-无相交元素");
        }

    算法文件地址

    约瑟夫环

相关推荐
无限码力7 小时前
科大讯飞秋招笔试真题 - 字符拼接 & 字典序最小的字符串拼接 & 圆心覆盖
算法·秋招·科大讯飞·科大讯飞笔试真题
Lips6117 小时前
第四章 决策树
算法·决策树·机器学习
YuTaoShao7 小时前
【LeetCode 每日一题】2053. 数组中第 K 个独一无二的字符串
算法·leetcode·职场和发展
朔北之忘 Clancy8 小时前
第二章 分支结构程序设计(3)
c++·算法·青少年编程·竞赛·教材·考级·讲义
想逃离铁厂的老铁8 小时前
Day42 >> 188、买卖股票的最佳时机IV + 309.最佳买卖股票时机含冷冻期 + 714.买卖股票的最佳时机含手续费
算法·leetcode·职场和发展
wu_asia8 小时前
方阵对角线元素乘积计算
数据结构·算法
想逃离铁厂的老铁9 小时前
Day43 >> 300.最长递增子序列 + 674. 最长连续递增序列+ 718. 最长重复子数组
数据结构·算法
Yzzz-F9 小时前
P6648 [CCC 2019] Triangle: The Data Structure [st表]
算法
LateFrames9 小时前
泰勒级数:从 “单点” 到 “理论与实践的鸿沟”
学习·算法
武帝为此9 小时前
【RC4加密算法介绍】
网络·python·算法