Python คะแนน: 2 1.5 1.25
นี่เป็นการรวมกันโดยตรงระหว่างคำตอบของ Primo กับคำตอบของฉัน ดังนั้นให้เครดิตกับเขาด้วย!
หลักฐานยังอยู่ในระหว่างดำเนินการ แต่นี่คือรหัสที่จะเล่นด้วย! หากคุณสามารถหาตัวอย่างเคาน์เตอร์ที่มีคะแนนมากกว่า 1.25 (หรือหากมีข้อผิดพลาด) แจ้งให้เราทราบ!
ปัจจุบันกรณีที่เลวร้ายที่สุดคือ:
aa ... aa dcb ... cbd
โดยที่มีตัวอักษร " n ", "b", "c", และ "" (ช่องว่าง) และ "d" สองตัว ความยาวของสตริงเป็น4n + 2และจำนวนที่ได้รับมอบหมายเป็น5n + 2ให้คะแนนของ5/4 = 1.25
อัลกอริทึมทำงานในสองขั้นตอน:
- ค้นหา
k
สิ่งนั้นstring[k]
และstring[n-1-k]
เป็นขอบเขตของคำ
- เรียกใช้อัลกอริทึมการย้อนกลับคำใด ๆ บน
string[:k]+string[n-1-k:]
(เช่นการต่อกันของตัวอักษรตัวแรกk
และk
ตัวสุดท้าย) ด้วยการปรับเปลี่ยนเล็กน้อย
ที่n
มีความยาวของสตริง
การปรับปรุงอัลกอริธึมนี้มาจาก "การดัดแปลงเล็ก ๆ " ในขั้นตอนที่ 2 โดยพื้นฐานแล้วมันคือความรู้ที่ว่าในสตริงที่ต่อกันตัวละครที่อยู่ในตำแหน่งk
และk+1
เป็นขอบเขตของคำ (ซึ่งหมายถึงพวกมันคือช่องว่าง และเพื่อให้เราสามารถแทนที่ตัวละครที่อยู่ในตำแหน่งk
และk+1
ด้วยตัวอักษรที่สอดคล้องกันในสตริงสุดท้าย, บันทึกงานที่มอบหมายไม่กี่ สิ่งนี้จะลบกรณีที่เลวร้ายที่สุดออกจากอัลกอริทึมการกลับคำของโฮสต์
มีหลายกรณีที่เราไม่สามารถหาได้จริงk
ในกรณีนั้นเราเพียงแค่เรียกใช้ "อัลกอริทึมการกลับคำใด ๆ " ในสตริงทั้งหมด
รหัสนี้มีความยาวพอที่จะรองรับทั้งสี่กรณีนี้ในการรันอัลกอริทึมการกลับคำในสตริง "concatenated":
- เมื่อ
k
ไม่พบ ( f_long = -2
)
- เมื่อ
string[k] != ' ' and string[n-1-k] != ' '
( f_long = 0
)
- เมื่อ
string[k] != ' ' and string[n-1-k] == ' '
( f_long = 1
)
- เมื่อ
string[k] == ' ' and string[n-1-k] != ' '
( f_long = -1
)
ฉันแน่ใจว่ารหัสสามารถย่อ ปัจจุบันมันยาวเพราะฉันไม่ได้เห็นภาพที่ชัดเจนของอัลกอริทึมทั้งหมดในตอนแรก ฉันแน่ใจว่าสามารถออกแบบให้แสดงในรหัสที่สั้นลง =)
ตัวอย่างการวิ่ง (อย่างแรกคือของฉันที่สองคือของพรีโม่):
ป้อนสตริง: a bc def ghij
"ghij def bc a": 9, 13, 0.692
"ghij def bc a": 9, 13, 0.692
ป้อนสตริง: ab cdefghijklmnopqrstuvw xyz
"zyxwvutsrqponmlkjihgf edc ab": 50, 50, 1.000
"zyxwvutsrqponmlkjihgf edc ab": 51, 50, 1.020
ป้อนสตริง: abcdefg hijklmnopqrstuvwx
"hijklmnopqrstuvwx gfedcb a": 38, 31, 1.226
"hijklmnopqrstuvwx gfedcb a": 38, 31, 1.226
ป้อนสตริง: a bc de fg hi jk lm ไม่มี pq rs tu vw xy zc
"zc xy vw tu rs pq no lm jk hi fg de bc a": 46, 40, 1.150
"zc xy vw tu rs pq no lm jk hi fg de bc a": 53, 40, 1.325
ป้อนสตริง: aaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaa dcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbd
"dcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbd aaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaa เป็น": 502, 402, 1.249
"dcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbcbd aaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaa เป็น": 502, 402, 1.249
คุณจะเห็นว่าคะแนนเกือบจะเหมือนกันยกเว้นกรณีที่แย่ที่สุดของอัลกอริธึมการกลับคำของโฮสต์ในตัวอย่างที่สามซึ่งวิธีการของฉันให้คะแนนน้อยกว่า 1.25
DEBUG = False
def find_new_idx(string, pos, char, f_start, f_end, b_start, b_end, f_long):
if DEBUG: print 'Finding new idx for s[%d] (%s)' % (pos, char)
if f_long == 0:
f_limit = f_end-1
b_limit = b_start
elif f_long == 1:
f_limit = f_end-1
b_limit = b_start+1
elif f_long == -1:
f_limit = f_end-2
b_limit = b_start
elif f_long == -2:
f_limit = f_end
b_limit = b_start
if (f_start <= pos < f_limit or b_limit < pos < b_end) and char == ' ':
word_start = pos
word_end = pos+1
else:
if pos < f_limit+1:
word_start = f_start
if DEBUG: print 'Assigned word_start from f_start (%d)' % f_start
elif pos == f_limit+1:
word_start = f_limit+1
if DEBUG: print 'Assigned word_start from f_limit+1 (%d)' % (f_limit+1)
elif b_limit <= pos:
word_start = b_limit
if DEBUG: print 'Assigned word_start from b_limit (%d)' % b_limit
elif b_limit-1 == pos:
word_start = b_limit-1
if DEBUG: print 'Assigned word_start from b_limit-1 (%d)' % (b_limit-1)
i = pos
while f_start <= i <= f_limit or 0 < b_limit <= i < b_end:
if i==f_limit or i==b_limit:
cur_char = 'a'
elif i!=pos:
cur_char = string[i]
else:
cur_char = char
if cur_char == ' ':
word_start = i+1
if DEBUG: print 'Assigned word_start from loop'
break
i -= 1
if b_limit <= pos:
word_end = b_end
if DEBUG: print 'Assigned word_end from b_end (%d)' % b_end
elif b_limit-1 == pos:
word_end = b_limit
if DEBUG: print 'Assigned word_end from b_limit (%d)' % (b_limit)
elif pos < f_limit+1:
word_end = f_limit+1
if DEBUG: print 'Assigned word_end from f_limit+1 (%d)' % (f_limit+1)
elif pos == f_limit+1:
word_end = f_limit+2
if DEBUG: print 'Assigned word_end from f_limit+2 (%d)' % (f_limit+2)
i = pos
while f_start <= i <= f_limit or 0 < b_limit <= i < b_end:
if i==f_limit or i==b_limit:
cur_char = 'a'
elif i!=pos:
cur_char = string[i]
else:
cur_char = char
if cur_char == ' ':
word_end = i
if DEBUG: print 'Assigned word_end from loop'
break
i += 1
if DEBUG: print 'start, end: %d, %d' % (word_start, word_end)
word_len = word_end - word_start
offset = word_start-f_start
result = (b_end-offset-(word_end-pos)) % b_end
if string[result] == ' ' and (b_start == -1 or result not in {f_end-1, b_start}):
return len(string)-1-result
else:
return result
def process_loop(string, start_idx, f_start, f_end, b_start, b_end=-1, f_long=-2, dry_run=False):
assignments = 0
pos = start_idx
tmp = string[pos]
processed_something = False
count = 0
while pos != start_idx or not processed_something:
count += 1
if DEBUG and count > 20:
print '>>>>>Break!<<<<<'
break
new_pos = find_new_idx(string, pos, tmp, f_start, f_end, b_start, b_end, f_long)
if DEBUG:
if dry_run:
print 'Test:',
else:
print '\t',
print 'New idx for s[%d] (%s): %d (%s)' % (pos, tmp, new_pos, string[new_pos])
if dry_run:
tmp = string[new_pos]
if new_pos == dry_run:
return True
elif pos == new_pos:
break
elif tmp == string[new_pos]:
pass
else:
tmp, string[new_pos] = string[new_pos], tmp
assignments += 1
pos = new_pos
processed_something = True
if dry_run:
return False
return assignments
def reverse(string, f_start, f_end, b_start, b_end=-1, f_long=-2):
if DEBUG: print 'reverse: %d %d %d %d %d' % (f_start, f_end, b_start, b_end, f_long)
if DEBUG: print
if DEBUG: print ''.join(string)
assignments = 0
n = len(string)
if b_start == -1:
for i in range(f_start, f_end):
if string[i] == ' ':
continue
if DEBUG: print 'Starting from i=%d' % i
if any(process_loop(string, j, f_start, f_end, -1, f_end, dry_run=i) for j in range(f_start, i) if string[j] != ' '):
continue
if DEBUG:
print
print 'Finished test'
assignments += process_loop(string, i, f_start, f_end, -1, f_end)
if DEBUG: print
if DEBUG: print ''.join(string)
for i in range(f_start, (f_start+f_end-1)/2):
if (string[i] == ' ' and string[n-1-i] != ' ') or (string[i] != ' ' and string[n-1-i] == ' '):
string[i], string[n-1-i] = string[n-1-i], string[i]
assignments += 2
else:
for i in range(f_start, f_end)+range(b_start, b_end):
if string[i] == ' ' and i not in {f_end-1, b_start}:
continue
if DEBUG: print 'Starting from i=%d' % i
if any(process_loop(string, j, f_start, f_end, b_start, b_end, f_long, i) for j in range(f_start, f_end)+range(b_start, b_end) if j<i and (string[j] != ' ' or j in {f_end-1, b_start})):
continue
assignments += process_loop(string, i, f_start, f_end, b_start, b_end, f_long)
if DEBUG: print
if DEBUG: print ''.join(string)
for i in range(f_start, f_end-1):
if (string[i] == ' ' and string[n-1-i] != ' ') or (string[i] != ' ' and string[n-1-i] == ' '):
string[i], string[n-1-i] = string[n-1-i], string[i]
assignments += 2
return assignments
class SuperList(list):
def index(self, value, start_idx=0):
try:
return self[:].index(value, start_idx)
except ValueError:
return -1
def rindex(self, value, end_idx=-1):
end_idx = end_idx % (len(self)+1)
try:
result = end_idx - self[end_idx-1::-1].index(value) - 1
except ValueError:
return -1
return result
def min_reverse(string):
assignments = 0
lower = 0
upper = len(string)
while lower < upper:
front = string.index(' ', lower) % (upper+1)
back = string.rindex(' ', upper)
while abs(front-lower - (upper-1-back)) > 1 and front < back:
if front-lower < (upper-1-back):
front = string.index(' ', front+1) % (upper+1)
else:
back = string.rindex(' ', back)
if DEBUG: print lower, front, back, upper
if front > back:
break
if DEBUG: print lower, front, back, upper
if abs(front-lower - (upper-1-back)) > 1:
assignments += reverse(string, lower, upper, -1)
lower = upper
elif front-lower < (upper-1-back):
assignments += reverse(string, lower, front+1, back+1, upper, -1)
lower = front+1
upper = back+1
elif front-lower > (upper-1-back):
assignments += reverse(string, lower, front, back, upper, 1)
lower = front
upper = back
else:
assignments += reverse(string, lower, front, back+1, upper, 0)
lower = front+1
upper = back
return assignments
def minier_find_new_idx(string, pos, char):
n = len(string)
try:
word_start = pos - next(i for i, char in enumerate(string[pos::-1]) if char == ' ') + 1
except:
word_start = 0
try:
word_end = pos + next(i for i, char in enumerate(string[pos:]) if char == ' ')
except:
word_end = n
word_len = word_end - word_start
offset = word_start
result = (n-offset-(word_end-pos))%n
if string[result] == ' ':
return n-result-1
else:
return result
def minier_process_loop(string, start_idx, dry_run=False):
assignments = 0
pos = start_idx
tmp = string[pos]
processed_something = False
while pos != start_idx or not processed_something:
new_pos = minier_find_new_idx(string, pos, tmp)
#print 'New idx for s[%d] (%s): %d (%s)' % (pos, tmp, new_pos, string[new_pos])
if pos == new_pos:
break
elif dry_run:
tmp = string[new_pos]
if new_pos == dry_run:
return True
elif tmp == string[new_pos]:
pass
else:
tmp, string[new_pos] = string[new_pos], tmp
assignments += 1
pos = new_pos
processed_something = True
if dry_run:
return False
return assignments
def minier_reverse(string):
assignments = 0
for i in range(len(string)):
if string[i] == ' ':
continue
if any(minier_process_loop(string, j, dry_run=i) for j in range(i) if string[j] != ' '):
continue
assignments += minier_process_loop(string, i)
n = len(string)
for i in range(n/2):
if string[i] == ' ' and string[n-i-1] != ' ':
string[i], string[n-i-1] = string[n-i-1], string[i]
assignments += 2
elif string[n-i-1] == ' ' and string[i] != ' ':
string[i], string[n-i-1] = string[n-i-1], string[i]
assignments += 2
return assignments
def main():
while True:
str_input = raw_input('Enter string: ')
string = SuperList(str_input)
result = min_reverse(string)
n = len(string)
print '"%s": %d, %d, %.3f' % (''.join(string), result, n, 1.0*result/n)
string = SuperList(str_input)
result2 = minier_reverse(string)
print '"%s": %d, %d, %.3f' % (''.join(string), result2, n, 1.0*result2/n)
if __name__ == '__main__':
main()
Python คะแนน: 1.5
จำนวนที่แน่นอนของการมอบหมายสามารถประมาณโดยสูตร:
n <= 1.5 * ความยาว (สตริง)
กับกรณีที่เลวร้ายที่สุด:
abcdefghi jklmnopqrstuvwxyzzz
กับ 55 การมอบหมายบนสตริงที่มีความยาว 37
แนวคิดนี้คล้ายกับรุ่นก่อนหน้าของฉันมันแค่นั้นในรุ่นนี้ฉันพยายามค้นหาคำนำหน้าและคำต่อท้ายที่ขอบเขตของคำที่มีความยาวต่างกันมากที่สุด 1 จากนั้นฉันเรียกใช้อัลกอริทึมก่อนหน้าของฉันบนคำนำหน้าและคำต่อท้ายนั้น . จากนั้นดำเนินการต่อในส่วนที่ยังไม่ได้ดำเนินการ
ตัวอย่างเช่นสำหรับกรณีที่เลวร้ายที่สุดก่อนหน้านี้:
AB | AB | ค
ก่อนอื่นเราจะใช้คำว่า "ab" และ "c" (การมอบหมาย 4 ครั้ง) เพื่อ:
c | AB | AB
เรารู้ว่าในขอบเขตที่เคยเป็นพื้นที่ (มีหลายกรณีที่ต้องจัดการ แต่คุณสามารถทำได้) ดังนั้นเราไม่จำเป็นต้องเข้ารหัสพื้นที่ที่ขอบเขตนี่คือการปรับปรุงหลักจากอัลกอริทึมก่อนหน้านี้ .
จากนั้นในที่สุดเราก็พบกับตัวละครสี่ตัวที่จะได้รับ:
cba ab
ในการมอบหมายทั้งหมด 8 รายการซึ่งเหมาะสมที่สุดสำหรับกรณีนี้เนื่องจากมีการเปลี่ยนแปลงอักขระทั้งหมด 8 ตัว
สิ่งนี้จะกำจัดกรณีที่เลวร้ายที่สุดในอัลกอริทึมก่อนหน้าเนื่องจากกรณีที่แย่ที่สุดในอัลกอริทึมก่อนหน้าจะถูกกำจัด
ดูตัวอย่างการวิ่ง (และเปรียบเทียบกับคำตอบของ @ primo - เขาคือบรรทัดที่สอง):
ป้อนสตริง: ฉันสามารถทำอะไรก็ได้
"ฉันสามารถทำอะไรก็ได้": 20, 17
"ฉันสามารถทำอะไรก็ได้": 17, 17
ป้อนสตริง: abcdef ghijklmnopqrs
"ghijklmnopqrs fedcb a": 37, 25
"ghijklmnopqrs fedcb a": 31, 25
ป้อนสตริง: abcdef ghijklmnopqrst
"ghijklmnopqrst fedcb a": 38, 26
"ghijklmnopqrst fedcb a": 32, 26
ป้อนสตริง: abcdefghi jklmnozzzzzzzzzzzzzzzzzzz
"jklmnozzzzzzzzzzzzzzzzzzz ihgfedcb a": 59, 41
"jklmnozzzzzzzzzzzzzzzzzzz ihgfedcb a": 45, 41
ป้อนสตริง: abcdefghi jklmnopqrstuvwxyzzz
"jklmnopqrstuvwxyzzz ihgfedcb a": 55, 37
"jklmnopqrstuvwxyzzz ihgfedcb a": 45, 37
ป้อนสตริง: ab abababababac
"cababababababa ab": 30, 30
"cababababababa ab": 31, 30
ป้อนสตริง: ab ababababababc
"cbababababababa ab": 32, 32
"cbababababababa ab": 33, 32
ป้อนสตริง: abc d abc
"abc d abc": 0, 9
"abc d abc": 0, 9
ป้อนสตริง: abc dca
"acd abc": 6, 9
"acd abc": 4, 9
ป้อนสตริง: abc abababababc
"cbabababababa abc": 7, 29
"cbabababababa abc": 5, 29
โดยทั่วไปแล้วคำตอบของ Primo จะดีกว่าถึงแม้ว่าในบางกรณีฉันสามารถได้เปรียบ 1 แต้ม =)
รหัสของเขาสั้นกว่าของฉันมากฮ่าฮ่า
DEBUG = False
def find_new_idx(string, pos, char, f_start, f_end, b_start, b_end, f_long):
if DEBUG: print 'Finding new idx for s[%d] (%s)' % (pos, char)
if f_long == 0:
f_limit = f_end-1
b_limit = b_start
elif f_long == 1:
f_limit = f_end-1
b_limit = b_start+1
elif f_long == -1:
f_limit = f_end-2
b_limit = b_start
elif f_long == -2:
f_limit = f_end
b_limit = b_start
if (f_start <= pos < f_limit or b_limit < pos < b_end) and (char == ' ' or char.isupper()):
word_start = pos
word_end = pos+1
else:
if pos < f_limit+1:
word_start = f_start
if DEBUG: print 'Assigned word_start from f_start (%d)' % f_start
elif pos == f_limit+1:
word_start = f_limit+1
if DEBUG: print 'Assigned word_start from f_limit+1 (%d)' % (f_limit+1)
elif b_limit <= pos:
word_start = b_limit
if DEBUG: print 'Assigned word_start from b_limit (%d)' % b_limit
elif b_limit-1 == pos:
word_start = b_limit-1
if DEBUG: print 'Assigned word_start from b_limit-1 (%d)' % (b_limit-1)
i = pos
if not (i < f_limit and b_limit < i):
i -= 1
while f_start <= i < f_limit or 0 < b_limit < i < b_end:
if i!=pos:
cur_char = string[i]
else:
cur_char = char
if cur_char == ' ' or cur_char.isupper():
word_start = i+1
if DEBUG: print 'Assigned word_start from loop'
break
i -= 1
if b_limit <= pos:
word_end = b_end
if DEBUG: print 'Assigned word_end from b_end (%d)' % b_end
elif b_limit-1 == pos:
word_end = b_limit
if DEBUG: print 'Assigned word_end from b_limit (%d)' % (b_limit)
elif pos < f_limit+1:
word_end = f_limit+1
if DEBUG: print 'Assigned word_end from f_limit+1 (%d)' % (f_limit+1)
elif pos == f_limit+1:
word_end = f_limit+2
if DEBUG: print 'Assigned word_end from f_limit+2 (%d)' % (f_limit+2)
i = pos
if not (i < f_limit and b_limit < i):
i += 1
while f_start <= i < f_limit or 0 < b_limit < i < b_end:
if i!=pos:
cur_char = string[i]
else:
cur_char = char
if cur_char == ' ' or cur_char.isupper():
word_end = i
if DEBUG: print 'Assigned word_end from loop'
break
i += 1
if DEBUG: print 'start, end: %d, %d' % (word_start, word_end)
word_len = word_end - word_start
offset = word_start-f_start
return (b_end-offset-(word_end-pos)) % b_end
def process_loop(string, start_idx, f_start, f_end, b_start, b_end=-1, f_long=-2, dry_run=False):
assignments = 0
pos = start_idx
tmp = string[pos]
processed_something = False
count = 0
while pos != start_idx or not processed_something:
count += 1
if count > 20:
if DEBUG: print 'Break!'
break
new_pos = find_new_idx(string, pos, tmp, f_start, f_end, b_start, b_end, f_long)
#if dry_run:
# if DEBUG: print 'Test:',
if DEBUG: print 'New idx for s[%d] (%s): %d (%s)' % (pos, tmp, new_pos, string[new_pos])
if pos == new_pos:
break
elif dry_run:
tmp = string[new_pos]
if new_pos == dry_run:
return True
elif tmp == string[new_pos]:
pass
elif tmp == ' ':
if b_start!=-1 and new_pos in {f_end-1, b_start}:
tmp, string[new_pos] = string[new_pos], tmp
else:
tmp, string[new_pos] = string[new_pos], '@'
assignments += 1
elif string[new_pos] == ' ':
if b_start!=-1 and new_pos in {f_end-1, b_start}:
tmp, string[new_pos] = string[new_pos], tmp
else:
tmp, string[new_pos] = string[new_pos], tmp.upper()
assignments += 1
else:
tmp, string[new_pos] = string[new_pos], tmp
assignments += 1
pos = new_pos
processed_something = True
if dry_run:
return False
return assignments
def reverse(string, f_start, f_end, b_start, b_end=-1, f_long=-2):
if DEBUG: print 'reverse: %d %d %d %d %d' % (f_start, f_end, b_start, b_end, f_long)
if DEBUG: print
if DEBUG: print ''.join(string)
assignments = 0
if b_start == -1:
for i in range(f_start, (f_start+f_end)/2):
if DEBUG: print 'Starting from i=%d' % i
if any(process_loop(string, j, f_start, f_end, -1, f_end, dry_run=i) for j in range(f_start, i)):
continue
assignments += process_loop(string, i, f_start, f_end, -1, f_end)
if DEBUG: print
if DEBUG: print ''.join(string)
else:
for i in range(f_start, f_end):
if DEBUG: print 'Starting from i=%d' % i
if any(process_loop(string, j, f_start, f_end, b_start, b_end, f_long, i) for j in range(f_start, i)):
continue
assignments += process_loop(string, i, f_start, f_end, b_start, b_end, f_long)
if DEBUG: print
if DEBUG: print ''.join(string)
for i in range(len(string)):
if string[i] == '@':
string[i] = ' '
assignments += 1
if string[i].isupper():
string[i] = string[i].lower()
assignments += 1
return assignments
class SuperList(list):
def index(self, value, start_idx=0):
try:
return self[:].index(value, start_idx)
except ValueError:
return -1
def rindex(self, value, end_idx=-1):
end_idx = end_idx % (len(self)+1)
try:
result = end_idx - self[end_idx-1::-1].index(value) - 1
except ValueError:
return -1
return result
def min_reverse(string):
# My algorithm
assignments = 0
lower = 0
upper = len(string)
while lower < upper:
front = string.index(' ', lower) % (upper+1)
back = string.rindex(' ', upper)
while abs(front-lower - (upper-1-back)) > 1 and front < back:
if front-lower < (upper-1-back):
front = string.index(' ', front+1) % (upper+1)
else:
back = string.rindex(' ', back)
if DEBUG: print lower, front, back, upper
if front > back:
break
if DEBUG: print lower, front, back, upper
if abs(front-lower - (upper-1-back)) > 1:
assignments += reverse(string, lower, upper, -1)
lower = upper
elif front-lower < (upper-1-back):
assignments += reverse(string, lower, front+1, back+1, upper, -1)
lower = front+1
upper = back+1
elif front-lower > (upper-1-back):
assignments += reverse(string, lower, front, back, upper, 1)
lower = front
upper = back
else:
assignments += reverse(string, lower, front, back+1, upper, 0)
lower = front+1
upper = back
return assignments
def minier_find_new_idx(string, pos, char):
n = len(string)
try:
word_start = pos - next(i for i, char in enumerate(string[pos::-1]) if char == ' ') + 1
except:
word_start = 0
try:
word_end = pos + next(i for i, char in enumerate(string[pos:]) if char == ' ')
except:
word_end = n
word_len = word_end - word_start
offset = word_start
result = (n-offset-(word_end-pos))%n
if string[result] == ' ':
return n-result-1
else:
return result
def minier_process_loop(string, start_idx, dry_run=False):
assignments = 0
pos = start_idx
tmp = string[pos]
processed_something = False
while pos != start_idx or not processed_something:
new_pos = minier_find_new_idx(string, pos, tmp)
#print 'New idx for s[%d] (%s): %d (%s)' % (pos, tmp, new_pos, string[new_pos])
if pos == new_pos:
break
elif dry_run:
tmp = string[new_pos]
if new_pos == dry_run:
return True
elif tmp == string[new_pos]:
pass
else:
tmp, string[new_pos] = string[new_pos], tmp
assignments += 1
pos = new_pos
processed_something = True
if dry_run:
return False
return assignments
def minier_reverse(string):
# primo's answer for comparison
assignments = 0
for i in range(len(string)):
if string[i] == ' ':
continue
if any(minier_process_loop(string, j, dry_run=i) for j in range(i) if string[j] != ' '):
continue
assignments += minier_process_loop(string, i)
n = len(string)
for i in range(n/2):
if string[i] == ' ' and string[n-i-1] != ' ':
string[i], string[n-i-1] = string[n-i-1], string[i]
assignments += 2
elif string[n-i-1] == ' ' and string[i] != ' ':
string[i], string[n-i-1] = string[n-i-1], string[i]
assignments += 2
return assignments
def main():
while True:
str_input = raw_input('Enter string: ')
string = SuperList(str_input)
result = min_reverse(string)
print '"%s": %d, %d' % (''.join(string), result, len(string))
string = SuperList(str_input)
result2 = minier_reverse(string)
print '"%s": %d, %d' % (''.join(string), result2, len(string))
if __name__ == '__main__':
main()
Python, คะแนน: asymptotically 2, ในกรณีปกติน้อยกว่ามาก
ลบรหัสเก่าออกเนื่องจากข้อ จำกัด ด้านพื้นที่
ความคิดที่จะย้ำผ่านแต่ละดัชนีและสำหรับแต่ละดัชนีi
เราใช้ตัวอักษรในการคำนวณตำแหน่งใหม่j
จดจำตัวละครในตำแหน่งที่j
กำหนดตัวอักษรที่i
จะและซ้ำด้วยตัวอักษรที่ดัชนีj
j
เนื่องจากเราต้องการข้อมูลอวกาศเพื่อคำนวณตำแหน่งใหม่ฉันจึงเข้ารหัสพื้นที่เก่าเป็นจดหมายตัวพิมพ์ใหญ่เวอร์ชันใหม่และช่องว่างใหม่เป็น '@'