diff --git "a/src/main/java/\347\256\227\346\263\225/\347\272\246\347\221\237\345\244\253\347\216\257/LeetCodeCN_0062_Josephus.java" "b/src/main/java/\347\256\227\346\263\225/\347\272\246\347\221\237\345\244\253\347\216\257/LeetCodeCN_0062_Josephus.java" new file mode 100644 index 0000000000000000000000000000000000000000..0f5561fac9e88d98276bb05a781906e3a89db917 --- /dev/null +++ "b/src/main/java/\347\256\227\346\263\225/\347\272\246\347\221\237\345\244\253\347\216\257/LeetCodeCN_0062_Josephus.java" @@ -0,0 +1,167 @@ +package 算法.约瑟夫环; + +// TODO +// 约瑟夫环问题 +// 给定一个链表头节点head,和一个正数m +// 从头开始,每次数到m就杀死当前节点 +// 然后被杀节点的下一个节点从1开始重新数, +// 周而复始直到只剩一个节点,返回最后的节点 +// Leetcode : +// https://leetcode-cn.com/problems/yuan-quan-zhong-zui-hou-sheng-xia-de-shu-zi-lcof/ +// +// 约瑟夫环问题 +// +// 现在一共有i个节点,数到m就杀死节点,最终会活下来的节点,请返回它在有i个节点时候的编号 +// +// 暴力方法: +// 如果总共有N个节点, 要杀死N-1个节点, 要杀死的每一个节点都要数到K个,所以暴力方法的复杂度是: O(N*K) +// +// 可以优化到:O(N) +// +// tips 考虑到最后情况,只剩一个节点,这一个节点在自己的小链表中的编号就是1号节点,当只剩1个节点的时候, 活着的编号就是1, +// +// 假设我有一个公式 +// +// ``` +// f(留下后的编号) = 杀之前的编号, +// ``` +// +// 这个公式可以算出杀之前的编号 那最后一个节点1, 调一下这个函数, 就能算出2个节点时候,活着的编号是多少,再调一下这个函数, 就能算出3个节点时候,活着的编号是多少,依次往上调用, +// 直到N个节点, 一个节点也不少的时候, +// 算出来的就是最后活着的编号 +// +// 启发: 剃刀函数 y = x % i +// +// 环形链表中,报号和数字之间的对应的关系 号= (数-1)%i + 1 +// +// 旧:1234567 新:56X1234 然后画图找规律 旧 = (新+ S-1)%i+1 +// +// S->原链表被杀的编号 +// S = (M-1)%i+1 +// i->杀之前的长度 +// +// --> (新 + (m-1)) % i + 1 +// +// LeetCodeCN_0062_Josephus.java +// +// 扩展 +// +// 给参数N, 表示从1..N有这么多人, 坐成一个圈, 一起玩游戏. 每一次从一个数组中取一个数字, 当数到这个数字的人别杀掉. 比如:[3,1,5,2,7] +// 第一次数到3的人会被杀掉 下面从4开始取到1, 4被杀掉 最后只有1留下来 +// +// 当数字不够用的时候,回到开头继续取数字, 问最后编号为多少的人能活下来. +public class LeetCodeCN_0062_Josephus { + // 提交直接通过 + // 给定的编号是0~n-1的情况下,数到m就杀 + // 返回谁会活? + public int lastRemaining1(int n, int m) { + return getLive(n, m) - 1; + } + + // 以下设定是:给定的编号是1~n的情况下,数到m就杀 + // 返回谁会活? + public static int getLive(int n, int m) { + if (n == 1) { + return 1; + } + return (getLive(n - 1, m) + m - 1) % n + 1; + } + + // 给定的编号是0~n-1的情况下,数到m就杀 + // 返回谁会活? + // 这个版本是迭代版 + public int lastRemaining2(int n, int m) { + int ans = 1; + int r = 1; + while (r <= n) { + ans = (ans + m - 1) % (r++) + 1; + } + return ans - 1; + } + + // 以下的code针对单链表,不要提交 + public static class Node { + public int value; + public Node next; + + public Node(int data) { + this.value = data; + } + } + + public static Node josephusKill1(Node head, int m) { + if (head == null || head.next == head || m < 1) { + return head; + } + Node last = head; + while (last.next != head) { + last = last.next; + } + int count = 0; + while (head != last) { + if (++count == m) { + last.next = head.next; + count = 0; + } else { + last = last.next; + } + head = last.next; + } + return head; + } + + public static Node josephusKill2(Node head, int m) { + if (head == null || head.next == head || m < 1) { + return head; + } + Node cur = head.next; + int size = 1; // tmp -> list size + while (cur != head) { + size++; + cur = cur.next; + } + int live = getLive(size, m); // tmp -> service node position + while (--live != 0) { + head = head.next; + } + head.next = head; + return head; + } + + public static void printCircularList(Node head) { + if (head == null) { + return; + } + System.out.print("Circular List: " + head.value + " "); + Node cur = head.next; + while (cur != head) { + System.out.print(cur.value + " "); + cur = cur.next; + } + System.out.println("-> " + head.value); + } + + public static void main(String[] args) { + Node head1 = new Node(1); + head1.next = new Node(2); + head1.next.next = new Node(3); + head1.next.next.next = new Node(4); + head1.next.next.next.next = new Node(5); + head1.next.next.next.next.next = head1; + printCircularList(head1); + head1 = josephusKill1(head1, 3); + printCircularList(head1); + + Node head2 = new Node(1); + head2.next = new Node(2); + head2.next.next = new Node(3); + head2.next.next.next = new Node(4); + head2.next.next.next.next = new Node(5); + head2.next.next.next.next.next = head2; + printCircularList(head2); + head2 = josephusKill2(head2, 3); + printCircularList(head2); + + } + +} diff --git "a/src/main/java/\347\273\203\344\271\240\351\242\230/leetcode/cn/LeetCodeCN_0062_Josephus.java" "b/src/main/java/\347\273\203\344\271\240\351\242\230/leetcode/cn/LeetCodeCN_0062_Josephus.java" deleted file mode 100644 index 5d362d700f2e3d275f4b19c4430f62e144c6f1a0..0000000000000000000000000000000000000000 --- "a/src/main/java/\347\273\203\344\271\240\351\242\230/leetcode/cn/LeetCodeCN_0062_Josephus.java" +++ /dev/null @@ -1,166 +0,0 @@ -package 练习题.leetcode.cn; - -// TODO -//约瑟夫环问题 -// 给定一个链表头节点head,和一个正数m -// 从头开始,每次数到m就杀死当前节点 -// 然后被杀节点的下一个节点从1开始重新数, -// 周而复始直到只剩一个节点,返回最后的节点 -// Leetcode : -// https://leetcode-cn.com/problems/yuan-quan-zhong-zui-hou-sheng-xia-de-shu-zi-lcof/ -// -// 约瑟夫环问题 -// -// 现在一共有i个节点,数到m就杀死节点,最终会活下来的节点,请返回它在有i个节点时候的编号 -// -// 暴力方法: -// 如果总共有N个节点, 要杀死N-1个节点, 要杀死的每一个节点都要数到K个,所以暴力方法的复杂度是: O(N*K) -// -// 可以优化到:O(N) -// -// tips 考虑到最后情况,只剩一个节点,这一个节点在自己的小链表中的编号就是1号节点,当只剩1个节点的时候, 活着的编号就是1, -// -// 假设我有一个公式 -// -// ``` -// f(留下后的编号) = 杀之前的编号, -// ``` -// -// 这个公式可以算出杀之前的编号 那最后一个节点1, 调一下这个函数, 就能算出2个节点时候,活着的编号是多少,再调一下这个函数, 就能算出3个节点时候,活着的编号是多少,依次往上调用, 直到N个节点, 一个节点也不少的时候, -// 算出来的就是最后活着的编号 -// -// 启发: 剃刀函数 y = x % i -// -// 环形链表中,报号和数字之间的对应的关系 号= (数-1)%i + 1 -// -// 旧:1234567 新:56X1234 然后画图找规律 旧 = (新+ S-1)%i+1 -// -// S->原链表被杀的编号 -// S = (M-1)%i+1 -// i->杀之前的长度 -// -// --> (新 + (m-1)) % i + 1 -// -// LeetCodeCN_0062_Josephus.java -// -// 扩展 -// -// 给参数N, 表示从1..N有这么多人, 坐成一个圈, 一起玩游戏. 每一次从一个数组中取一个数字, 当数到这个数字的人别杀掉. 比如:[3,1,5,2,7] -// 第一次数到3的人会被杀掉 下面从4开始取到1, 4被杀掉 最后只有1留下来 -// -// 当数字不够用的时候,回到开头继续取数字, 问最后编号为多少的人能活下来. -public class LeetCodeCN_0062_Josephus { - // 提交直接通过 - // 给定的编号是0~n-1的情况下,数到m就杀 - // 返回谁会活? - public int lastRemaining1(int n, int m) { - return getLive(n, m) - 1; - } - - // 以下设定是:给定的编号是1~n的情况下,数到m就杀 - // 返回谁会活? - public static int getLive(int n, int m) { - if (n == 1) { - return 1; - } - return (getLive(n - 1, m) + m - 1) % n + 1; - } - - // 给定的编号是0~n-1的情况下,数到m就杀 - // 返回谁会活? - // 这个版本是迭代版 - public int lastRemaining2(int n, int m) { - int ans = 1; - int r = 1; - while (r <= n) { - ans = (ans + m - 1) % (r++) + 1; - } - return ans - 1; - } - - // 以下的code针对单链表,不要提交 - public static class Node { - public int value; - public Node next; - - public Node(int data) { - this.value = data; - } - } - - public static Node josephusKill1(Node head, int m) { - if (head == null || head.next == head || m < 1) { - return head; - } - Node last = head; - while (last.next != head) { - last = last.next; - } - int count = 0; - while (head != last) { - if (++count == m) { - last.next = head.next; - count = 0; - } else { - last = last.next; - } - head = last.next; - } - return head; - } - - public static Node josephusKill2(Node head, int m) { - if (head == null || head.next == head || m < 1) { - return head; - } - Node cur = head.next; - int size = 1; // tmp -> list size - while (cur != head) { - size++; - cur = cur.next; - } - int live = getLive(size, m); // tmp -> service node position - while (--live != 0) { - head = head.next; - } - head.next = head; - return head; - } - - public static void printCircularList(Node head) { - if (head == null) { - return; - } - System.out.print("Circular List: " + head.value + " "); - Node cur = head.next; - while (cur != head) { - System.out.print(cur.value + " "); - cur = cur.next; - } - System.out.println("-> " + head.value); - } - - public static void main(String[] args) { - Node head1 = new Node(1); - head1.next = new Node(2); - head1.next.next = new Node(3); - head1.next.next.next = new Node(4); - head1.next.next.next.next = new Node(5); - head1.next.next.next.next.next = head1; - printCircularList(head1); - head1 = josephusKill1(head1, 3); - printCircularList(head1); - - Node head2 = new Node(1); - head2.next = new Node(2); - head2.next.next = new Node(3); - head2.next.next.next = new Node(4); - head2.next.next.next.next = new Node(5); - head2.next.next.next.next.next = head2; - printCircularList(head2); - head2 = josephusKill2(head2, 3); - printCircularList(head2); - - } - -}