约瑟夫问题
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 }

浙公网安备 33010602011771号