-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathshiftk.py
105 lines (92 loc) · 2.18 KB
/
shiftk.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
"""
Consideration: Finetuning memory access patterns may speed things up by avoiding cache
misses. Though, you probably want to run a perf test first to see if the optimizations
are necessary.
"""
from math import gcd
from typing import List, Any
def swap(arr: List[Any], i: int, j: int) -> None:
"""In-place swap.
Swaps[1].
Reads[2].
Writes[2].
"""
arr[i], arr[j] = arr[j], arr[i]
def shift_cycle(arr: List[Any], k: int) -> None:
"""In-place shift.
Reads[n].
Writes[n].
Swap version:
while i != j:
i_next = (i + k) % n
swap(arr, i, i_next)
i = i_next
Swaps[n-gcd(n,k)].
"""
n = len(arr)
k = (-k % n + n) % n
if n == 0 or k == 0:
return
m = gcd(n, k)
for j in range(m):
i = (j + k) % n
temp = arr[i]
while i != j:
i_next = (i + k) % n
arr[i] = arr[i_next]
i = i_next
arr[j] = temp
def shift_simple(arr: List[Any], k: int) -> List[Any]:
n = len(arr)
k = (-k % n + n) % n
return arr[k:] + arr[:k]
def _reverse(arr: List[Any], i: int, j: int) -> None:
"""In-place reverse.
Swaps[(j-i+1)/2].
Reads[j-i+1].
Writes[j-i+1].
"""
while i < j:
swap(arr, i, j)
i += 1
j -= 1
def shift_reverse(arr: List[Any], k: int) -> None:
"""In-place shift.
Swaps[n/2+k/2+(n-k)/2] <= Swaps[n].
Reads[2n].
Writes[2n].
"""
n = len(arr)
k = (k % n + n) % n
if n == 0 or k == 0:
return
_reverse(arr, 0, n-1)
_reverse(arr, 0, k-1)
_reverse(arr, k, n-1)
nk = [
(5, 0),
(5, 2),
(5, 6),
(5, -3),
(5, -7),
(12, 4),
(12, 5),
(12, 6),
]
def check(n: int, k: int) -> None:
arr = list(range(n))
arr_simple = shift_simple(arr, k)
arr_cycle = list(arr)
shift_cycle(arr_cycle, k)
arr_reverse = list(arr)
shift_reverse(arr_reverse, k)
if arr_cycle != arr_simple:
print(f'Cycle {n} {k}:')
print(arr_cycle)
print(arr_simple)
if arr_reverse != arr_simple:
print(f'Reverse {n} {k}:')
print(arr_reverse)
print(arr_simple)
for n, k in nk:
check(n, k)