• 约瑟夫问题


    LeetCode 剑指offer62

    0,1,,n-1这n个数字排成一个圆圈,从数字0开始,每次从这个圆圈里删除第m个数字。求出这个圆圈里剩下的最后一个数字。

    这个问题是以弗拉维奥·约瑟夫命名的,他是1世纪的一名犹太历史学家。他在自己的日记中写道,他和他的40个战友被罗马军队包围在洞中。他们讨论是自杀还是被俘,最终决定自杀,并以抽签的方式决定谁杀掉谁。约瑟夫斯和另外一个人是最后两个留下的人。约瑟夫斯说服了那个人,他们将向罗马军队投降,不再自杀。约瑟夫斯把他的存活归因于运气或天意,他不知道是哪一个。 —— 【约瑟夫问题】维基百科

    一、模拟单向环形链表

    据题解大佬所言,LinkedList会超时,因为链表remove中删除复杂度为1,但查找到该索引需n;ArrayList相反是查找为1,删除为n。不过因为ArrayList删除是拷贝的后面元素是连续地址的,而链表需要大量访问非来纳许地址,因此耗时。

    复杂度为O(n2)

    class Solution {
        public int lastRemaining(int n, int m) {
            ArrayList<Integer> list = new ArrayList<>(n);
            for (int i = 0; i < n; i++) {
                list.add(i);
            }
            int idx = 0;
            while (n > 1) {
                idx = (idx + m - 1) % n;
                list.remove(idx);  // 注意remove后idx自动后移
                n--;
            }
            return list.get(0);
        }
    }

    二、数学解法

    f(n,m)与f(n-1,m)之间的关系:当n个数先删掉第一个坐标(m-1)%n时,可以看成n-1个数组成的环,其中首元素坐标为m。而f(n-1,m)的首元素坐标为0,因此 f(n,m) = ( f(n-1,m) + m ) % n。

    class Solution {
        public int lastRemaining(int n, int m) {
            int ans = 0;
            // 最后一轮剩下2个人,所以从2开始反推
            for (int i = 2; i <= n; i++) {
                ans = (ans + m) % i;
            }
            return ans;
        }
    }

    三、马拉车算法 Manacher's algorithm

    参考链接

    构造T,在每个字符两边添加‘#’,n+(n+1)统一成奇回文。 构造P对应以T中每个字符为中心的回文长度,寻找最大值。

    1、最大半径减1等于最长回文串的长度

    2、最长回文字符的起始位置(s中的索引)是中间位置(T或P中的索引)减去半径(P中的值+1)再除以2

    这里的P为回文长度,因此无需与半径做转换。

    public class Solution {
     2     // Transform S into T.
     3     // For example, S = "abba", T = "^#a#b#b#a#$".
     4     // ^ and $ signs are sentinels appended to each end to avoid bounds checking
     5     String preProcess(String s) {
     6         int n = s.length();
     7         if (n == 0) return "^$";
     8 
     9         String ret = "^";
    10         for (int i = 0; i < n; i++)
    11         {
    12             ret += "#" + s.substring(i, i + 1);
    13         }
    14         
    15         ret += "#$";
    16         return ret;
    17     }
    18     public String longestPalindrome(String s) {
    19         String T = preProcess(s);
    20         int length = T.length();
    21         int[] p = new int[length];
    22         int C = 0, R = 0;
    23         
    24         for (int i = 1; i < length - 1; i++)
    25         {
    26             int i_mirror = C - (i - C);
    27             int diff = R - i;
    28             if (diff >= 0)//当前i在C和R之间,可以利用回文的对称属性
    29             {
    30                 if (p[i_mirror] < diff)//i的对称点的回文长度在C的大回文范围内部
    31                 { p[i] = p[i_mirror]; }
    32                 else
    33                 {
    34                     p[i] = diff;
    35                     //i处的回文可能超出C的大回文范围了
    36                     while (T.charAt(i + p[i] + 1) == T.charAt(i - p[i] - 1))
    37                     { p[i]++; }
    38                     C = i;
    39                     R = i + p[i];
    40                 }
    41             }
    42             else
    43             {
    44                 p[i] = 0;
    45                 while (T.charAt(i + p[i] + 1) == T.charAt(i - p[i] - 1))
    46                 { p[i]++; }
    47                 C = i;
    48                 R = i + p[i];
    49             }
    50         }
    51 
    52         int maxLen = 0;
    53         int centerIndex = 0;
    54         for (int i = 1; i < length - 1; i++) {
    55             if (p[i] > maxLen) {
    56               maxLen = p[i];
    57               centerIndex = i;
    58             }
    59         }
    60         return s.substring((centerIndex - 1 - maxLen) / 2, (centerIndex - 1 - maxLen) / 2 + maxLen);        
    61     }
    62 }
  • 相关阅读:
    字符串系列复习
    点分治总结
    LCT总结
    网络流总结
    centOS7下安装GUI图形界面
    周记 2014.10.8
    周记 2014.9.28
    周记 2014.9.20
    tar命令
    [转]bit与byte
  • 原文地址:https://www.cnblogs.com/faded828x/p/13449374.html
Copyright © 2020-2023  润新知