经典应用之约瑟夫环问题

本文详细介绍了约瑟夫环问题的两种解决方案,包括环形链表法和数组遍历法。通过创建环形链表模拟过程,当报数到M时删除节点,直至只剩最后一个节点。同时,使用数组遍历法,当报数到M时标记该位置为无效,最终找出幸存者的位置。这两种方法都有效地解决了这一经典问题。
摘要由CSDN通过智能技术生成

经典应用之约瑟夫环问题

约瑟夫环

有N个人围成一圈,从第一个人开始报数,报到M被杀,然后下一个人继续从1开始报数,循环往复,直到剩最后一个,最后一个人的初始位置在哪里?

f(n,m)

f(3,3) -> 1
0 1 2
A B C1
A2 B

f(4,3) -> 0
0 1 2 3
A B C1 D
D A B2
D3 A

分析:
A)环形链表法

将每个人视作链表中的一个节点,当报数到m的时候,删除节点,直到剩下最后一个节点
当找到报数m-1的节点 node node.next = node.next.next
当只剩最后一个节点时 node.next = node

public static int josephus(int n, int m) {
        // 初始化环形链表
        int[] arr = new int[n];
        for (int i = 0; i < arr.length; i++) {
            arr[i] = i + 1;
        }
        ListNode node = ListNode.arrayToListNode(arr);
        ListNode.toCycle(node, 0);

        // 将每个人视作链表中的一个节点,当报数到m的时候,删除节点,直到剩下最后一个节点
        // 当找到报数m-1的节点  node  node.next = node.next.next
        // 当只剩最后一个节点时  node.next = node
        int cnt = 1;
        while (true) {
            if (cnt == m - 1) {
                System.out.println("删除节点" + node.next.val);
                node.next = node.next.next;
                cnt = 0;
            }
            node = node.next;
            cnt++;

            if (node.next == node) return node.val;
        }

    }

B)数组遍历法

将每个人视作数组中的一个元素,当报数到m的时候,使用占位符代表此人死掉了
当剩余人数 只有一人时 停止循环

public static int josephus1(int n, int m) {
        // 数组记录   初始值是0  使用-1代表当前元素  死掉
        int[] people = new int[n];

        // 人的索引
        int index = -1;
        // 报数 1 2 ... m
        int cnt = 0;
        // 剩余人数
        int remain = n;
        while (remain > 0) {
            index++;
            // 到达数组末端  重新从头遍历
            if (index >= n) index = 0;

            // 如果此人死掉  跳过  继续报数
            if (people[index] == -1) {
                continue;
            }

            // 报数到m  将index对应位置的元素  置为-1 (尸体)
            if (cnt == m) {
                people[index] = -1;
                cnt = 0;
                remain--;
            }

            cnt++;
        }

        return index;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值