สลับลำดับของคำในสตริง inplace


17

งาน

  • [a-z]+( [a-z]+)*คุณจะได้รับสตริงแน่นอนว่าการแข่งขัน
  • คุณต้องกลายพันธุ์ให้เป็นสตริงซึ่งมีคำเดียวกัน แต่เรียงกลับกันดังนั้น "สวัสดีทุกคน" จึงกลายเป็น "ทุกคนที่นั่นสวัสดี"
  • คุณไม่ได้รับอนุญาตให้ใช้หน่วยความจำเพิ่มเติมมากกว่าจำนวนคงที่ (ดังนั้นห้ามคัดลอกทั้งสตริงหรือทั้งคำลงในบัฟเฟอร์ที่คุณเพิ่งจัดสรร)
  • ไม่มีการ จำกัด เวลา การไม่มีประสิทธิภาพอย่างสิ้นหวังจะไม่เป็นอันตรายต่อคะแนนของคุณ
  • หากภาษาที่คุณเลือกไม่อนุญาตให้มีการกลายพันธุ์ของสตริงอาร์เรย์ของอักขระเป็นสิ่งทดแทนที่ยอมรับได้

คะแนนของคุณ

  • คะแนนของคุณจะถูกนับอย่างหมดจดจากจำนวนชุดที่คุณทำกับองค์ประกอบสตริง (คะแนนน้อยที่สุดจะดีที่สุด) ถ้าคุณใช้ฟังก์ชันไลบรารีที่เขียนไปยังสตริงการเขียนของมันก็จะถูกนับด้วย
  • สมมติว่าจำนวนของการมอบหมายงานที่คุณต้องการสำหรับการป้อนข้อมูลที่เป็นn (s) แล้วคะแนนของคุณเป็นสูงสุด (อวด, supremum) มากกว่าปัจจัยการผลิตทั้งหมดs (ตรงกับ regex ที่ระบุข้างต้น) ของn (s) / ความยาว (s) หากคุณไม่สามารถคำนวณได้อย่างแม่นยำคุณสามารถใช้ขอบเขตบนที่ต่ำที่สุดที่คุณสามารถพิสูจน์ได้
  • คุณสามารถทำลายการผูกหากคุณสามารถพิสูจน์ได้ว่าอัลกอริทึมของคุณใช้การมอบหมายน้อยกว่าแบบไม่แสดงอาการ (สามารถเกิดขึ้นได้แม้ว่าคุณจะมีคะแนนเท่ากันดูด้านล่าง) หากคุณไม่สามารถทำสิ่งนี้ได้คุณสามารถหยุดความสัมพันธ์โดยแสดงว่าคุณใช้หน่วยความจำเพิ่มเติมน้อยลง อย่างไรก็ตามเงื่อนไข tie-break แรกจะมีความสำคัญกว่าเสมอ
  • สำหรับอินพุตบางตัวต้องเปลี่ยนดังนั้นจึงไม่สามารถทำคะแนนได้น้อยกว่า 1
  • ฉันสามารถคิดถึงอัลกอริทึมอย่างง่ายที่มีคะแนน 2 (แต่ฉันไม่ได้ป้อน)

หมายเหตุเกี่ยวกับ suprema และเน็คไท

  • จำนวนสูงสุดของชุดตัวเลขคือจำนวนที่เล็กที่สุดที่ไม่เล็กกว่าค่าใด ๆ นี่เป็นเหมือนค่าสูงสุดของเซตยกเว้นเซตที่ไม่มีที่สิ้นสุดเช่น {2/3, 3/4, 4/5, 5/6, ... } ไม่มีอิลิเมนต์สูงสุดเดียว แต่จะยังมีค่าสูงสุด ในกรณีนี้ 1
  • หากคุณจัดการเพื่อ "บันทึก" เพียงจำนวนที่ได้รับมอบหมายอย่างต่อเนื่องมากกว่าอัลกอริทึมของคะแนน 2 ของฉัน (พูด) คะแนนของคุณจะยังคงเป็น 2 เพราะคุณจะเข้าใกล้ 2 โดยพลที่คุณป้อนมากขึ้น อย่างไรก็ตามคุณชนะการเดิมพันแบบแบ่งถ้ามันเป็นเช่นนั้น

1
ฉันจะเศร้านิดหน่อยถ้าทั้งหมดนี้เกิดขึ้นจากการส่งคะแนน 2 อันต่อการใช้หน่วยความจำของพวกเขา ผมส่วนใหญ่โพสต์คำถามนี้สงสัยว่าถ้าใครจะจัดการเพื่อให้ได้คะแนนน้อยกว่า 2
เบน Millwood

1
ฉันไม่มีหลักฐานที่เป็นทางการ แต่สัญชาตญาณของฉันบอกฉันว่าด้วยการ จำกัด พื้นที่คงที่มันเป็นไปไม่ได้ที่จะทำได้ดีกว่า 2 ถ้าคุณนับการประกาศตัวแปรสำหรับอวกาศฉันสามารถโกงและสร้างฟังก์ชันเวียนเกิดขึ้นได้ แต่นั่นเป็นการปลอมแปลงlittle-omega(1)พื้นที่โดยวางมันลงบนสแต็ก
misu

2
@bacchusbeale ใช่ แต่มันก็เป็นหน่วยความจำเสริมคงที่
Martin Ender

4
หากคุณบังคับใช้กฎอย่างเคร่งครัดดังนั้นจึงเป็นไปไม่ได้ที่จะเขียนโปรแกรมดังกล่าว สตริงอาจมีความยาวตามอำเภอใจและคุณจะต้องมีตัวแปรอย่างน้อยชนิดที่เก็บดัชนี ดังนั้นฉันต้องทำให้สายยาวพอที่จะเกินขอบเขตของตัวแปรของคุณ ในการจัดเก็บดัชนีอย่างน้อยหนึ่งหน่วยความจำที่จำเป็นหน่วยความจำที่จำเป็นของคุณจะเติบโตขึ้นพร้อมความยาวสตริง
IchBinKeinBaum

3
@IchBinKeinBaum ถูกต้องมันเป็นไปไม่ได้ที่จะทำงานนี้ด้วยO(1)พื้นที่เพิ่มเติม คุณต้องการO(log n)พื้นที่ในการจัดเก็บตำแหน่งดัชนีเนื่องจากจำนวนเต็ม k-bit สามารถเก็บไว้ในนั้นได้สำหรับสตริงที่มีความยาวสูงสุด2^kเท่านั้น การจำกัดความยาวของสตริงทำให้ความท้าทายค่อนข้างไม่มีจุดหมายเนื่องจากทุกอัลกอริทึมจะต้องใช้O(1)พื้นที่ด้วยวิธีนี้
Dennis

คำตอบ:


4

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

อัลกอริทึมทำงานในสองขั้นตอน:

  1. ค้นหาkสิ่งนั้นstring[k]และstring[n-1-k]เป็นขอบเขตของคำ
  2. เรียกใช้อัลกอริทึมการย้อนกลับคำใด ๆ บนstring[:k]+string[n-1-k:](เช่นการต่อกันของตัวอักษรตัวแรกkและkตัวสุดท้าย) ด้วยการปรับเปลี่ยนเล็กน้อย

ที่nมีความยาวของสตริง

การปรับปรุงอัลกอริธึมนี้มาจาก "การดัดแปลงเล็ก ๆ " ในขั้นตอนที่ 2 โดยพื้นฐานแล้วมันคือความรู้ที่ว่าในสตริงที่ต่อกันตัวละครที่อยู่ในตำแหน่งkและk+1เป็นขอบเขตของคำ (ซึ่งหมายถึงพวกมันคือช่องว่าง และเพื่อให้เราสามารถแทนที่ตัวละครที่อยู่ในตำแหน่งkและk+1ด้วยตัวอักษรที่สอดคล้องกันในสตริงสุดท้าย, บันทึกงานที่มอบหมายไม่กี่ สิ่งนี้จะลบกรณีที่เลวร้ายที่สุดออกจากอัลกอริทึมการกลับคำของโฮสต์

มีหลายกรณีที่เราไม่สามารถหาได้จริงkในกรณีนั้นเราเพียงแค่เรียกใช้ "อัลกอริทึมการกลับคำใด ๆ " ในสตริงทั้งหมด

รหัสนี้มีความยาวพอที่จะรองรับทั้งสี่กรณีนี้ในการรันอัลกอริทึมการกลับคำในสตริง "concatenated":

  1. เมื่อkไม่พบ ( f_long = -2)
  2. เมื่อstring[k] != ' ' and string[n-1-k] != ' '( f_long = 0)
  3. เมื่อstring[k] != ' ' and string[n-1-k] == ' '( f_long = 1)
  4. เมื่อ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เนื่องจากเราต้องการข้อมูลอวกาศเพื่อคำนวณตำแหน่งใหม่ฉันจึงเข้ารหัสพื้นที่เก่าเป็นจดหมายตัวพิมพ์ใหญ่เวอร์ชันใหม่และช่องว่างใหม่เป็น '@'


หากคุณสามารถลดจำนวนคำในกรณีที่แย่ลงให้อยู่ในความยาวของสตริง (พูดlength(string)/3โดยบังคับให้แต่ละคำในกรณีที่เลวร้ายที่สุดให้มีความยาวอย่างน้อย 2 อย่างใด) ดังนั้นคะแนนจะน้อยกว่า 2 (ในตัวอย่างด้านบนจะเป็น 1.67)
justhalf

1
ฉันเพิ่มตัวนับการสลับไปยังของฉัน จริงๆแล้วคุณชนะของฉันสำหรับกรณีที่เลวร้ายที่สุด (แต่ไม่ใช่กรณีทั่วไป) ต้องไปหาวิธีการแก้ไขที่มิ)
พรีโม่

บรรทัดที่ 127: if any(process_loop(...) for j in range(...))การนับจากกระบวนการเหล่านี้ไม่จำเป็นต้องนับรวมหรือไม่
โม่

นั่นไม่ได้ทำการมอบหมายใด ๆ หากคุณเห็นdry_runพารามิเตอร์ถูกตั้งค่าเป็นไม่ใช่ศูนย์ (ค่าเป็นi) ภายในprocess_loopถ้าdry_runไม่ใช่ศูนย์มันจะไม่ทำการมอบหมายใด ๆ
justhalf

1
ฉันคิดว่าฉันมีภาพที่ดีขึ้นในขณะนี้ ในสาระสำคัญมีวิธีการสองวิธีที่แตกต่างกันซึ่งมีพฤติกรรมกรณีที่เลวร้ายที่สุดมารวมกันเพื่อกำจัดกรณีที่เลวร้ายที่สุดสำหรับทั้ง ฉันชอบมัน. โดยทั่วไปฉันคิดว่านี่อาจเป็นวิธีที่ดีที่สุดที่จะใช้แม้ว่าจะมีวิธีการที่แตกต่างกันโดยสิ้นเชิง (หรือมากกว่า) อาจรวมกันเพื่อลดกรณีที่เลวร้ายยิ่งขึ้นไปอีก
โม่

14

Perl, คะแนน1.3̅

สำหรับแต่ละอักขระที่ไม่ใช่ช่องว่างจะทำการมอบหมายหนึ่งครั้งและสำหรับแต่ละอักขระเว้นวรรคสองการมอบหมาย เพราะตัวอักษรพื้นที่ไม่สามารถเป็นจำนวนเงินมากกว่าครึ่งหนึ่งจำนวนตัวอักษรคะแนนกรณีที่เลวร้ายที่สุดคือ1.5

อัลกอริทึมไม่เปลี่ยนแปลง แต่ฉันสามารถพิสูจน์ขอบเขตบนล่างได้ ให้เราทำสองข้อสังเกต:

  1. ช่องว่างตรงข้ามกับช่องว่างไม่จำเป็นต้องสลับ
  2. คำเดียวที่ตรงข้ามกับช่องว่างจะไม่ถูกสลับระหว่างเฟสหลัก แต่จะสิ้นสุดเพียงครั้งเดียวเท่านั้น

จากนั้นจะเห็นได้ว่าทฤษฎี 'กรณีที่เลวร้ายที่สุด' ที่มี asymptotically 1/2 ช่องว่างไม่ใช่กรณีที่เลวร้ายที่สุดเลย: ab c d e f g h i ...

$ echo ab c d e f g h i j k l m n o p q r s t u v w x y z|perl reverse-inplace.pl
z y x w v u t s r q p o n m l k j i h g f e d c ab
swaps: 51; len: 50
ratio: 1.02

ในความเป็นจริงมันค่อนข้างดี

เพื่อป้องกันการสังเกตหนึ่งและสองข้างต้นคำหนึ่งอักขระแต่ละตัวจะต้องมีการปรับตำแหน่งให้อยู่ตรงกลางของคำที่มีความยาวสามตัวอักษรขึ้นไป กรณีนี้จะแนะนำกรณีที่แย่ที่สุดที่มีช่องว่างแบบ asymptotically 1/3:a bcd a bcd a ... bc

$ echo a bcd a bcd a bcd a bcd a bcd a bc|perl reverse-inplace.pl
bc a bcd a bcd a bcd a bcd a bcd a
swaps: 45; len: 34
ratio: 1.32352941176471

หรือเท่ากันเพียงสองคำอักขระ: a bc de fg hi jk ...

$ echo a bc de fg hi jk lm no pq rs tu vx xy|perl reverse-inplace.pl
xy vx tu rs pq no lm jk hi fg de bc a
swaps: 49; len: 37
ratio: 1.32432432432432

เพราะกรณีที่เลวร้ายมี asymptotically 1/3 ช่องว่างคะแนนกรณีที่เลวร้ายจะกลายเป็น1.3

#!perl -l
use warnings;

$words = <>;
chomp($words);
$len = length($words);
$words .= ' ';
$spaces = 0;
# iterate over the string, count the spaces
$spaces++ while $words =~ m/ /g;

$origin = 0;
$o = vec($words, $origin, 8);
$cycle_begin = $origin;
$swaps = 0;

# this possibly terinates one iteration early,
# if the last char is a one-cycle (i.e. moves to its current location)
# one-cycles previous to the last are iterated, but not swapped.
while ($i++ < $len - $spaces || !$was_cycle) {
  $w_start = rindex($words, ' ', $origin);
  $w_end = index($words, ' ', $origin);
  $pos = ($origin - $w_start) - 1;
  $target = $len - ($w_end - $pos);
  $t = vec($words, $target, 8);

  if ($t == 32) {
    $target = $len - $target - 1;
    $t = vec($words, $target, 8);
  }

  # char is already correct, possibly a one-cycle
  if ($t != $o) {
    $swaps += 1;
    vec($words, $target, 8) = $o;
  }

  $origin = $target;
  $o = $t;
  if ($origin == $cycle_begin) {
    if ($i < $len - $spaces) {
      # backtrack through everything we've done up to this point
      # to find the next unswapped char ...seriously.
      $origin += 1;
      if (vec($words, $origin, 8) == 32) {
        $origin += 1;
      }
      $bt_origin = 0;
      $bt_cycle_begin = 0;
      while ($bt_cycle_begin < $origin) {
        $w_start = rindex($words, ' ', $bt_origin);
        $w_end = index($words, ' ', $bt_origin);
        $pos = ($bt_origin - $w_start) - 1;
        $target = $len - ($w_end - $pos);
        $t = vec($words, $target, 8);

        if ($t == 32) {
          $target = $len - $target - 1;
          $t = vec($words, $target, 8);
        }

        if ($target == $bt_cycle_begin) {
          $bt_origin = ++$bt_cycle_begin;
          if (vec($words, $bt_origin, 8) == 32) {
            $bt_origin = ++$bt_cycle_begin;
          }
        } else {
          $bt_origin = $target;
        }

        if ($target == $origin) {
          $origin += 1;
          if (vec($words, $origin, 8) == 32) {
            $origin += 1;
          }
          $bt_origin = $bt_cycle_begin = 0;
        }
      }
    }

    $cycle_begin = $origin;
    $o = vec($words, $origin, 8);
    $was_cycle = 1;
  } else {
    $was_cycle = 0;
  }
}

for $i (0..$len/2-1) {
  $mirror = $len - $i - 1;
  $o = vec($words, $i, 8);
  $m = vec($words, $mirror, 8);
  # if exactly one is a space...
  if (($o == 32) ^ ($m == 32)) {
    $swaps += 2;
    vec($words, $mirror, 8) = $o;
    vec($words, $i, 8) = $m;
  }
}

chop($words);
print $words;
print "swaps: $swaps; len: $len";
print 'ratio: ', $swaps/$len;

แก้ไข:เพิ่มตัวนับการแลกเปลี่ยนและอัตราส่วน

อินพุตถูกนำมาจาก stdin ตัวอย่างการใช้งาน:

$ echo where in the world is carmen sandiego|perl reverse-inplace.pl
sandiego carmen is world the in where
swaps: 35; len: 37
ratio: 0.945945945945946

วิธี

ในการเริ่มต้นอักขระตัวแรกของสตริงจะถูกย้ายไปยังปลายทางสุดท้าย ตัวละครที่เพิ่งเปลี่ยนจะถูกย้ายไปยังปลายทาง ฯลฯ ซึ่งจะดำเนินต่อไปจนกว่าจะพบกับเงื่อนไขข้อใดข้อหนึ่งในสองข้อนี้:

  1. ควรสลับอักขระด้วยช่องว่าง
    เมื่อสิ่งนี้เกิดขึ้นตัวละครจะไม่สลับกับช่องว่าง แต่จะเข้าสู่ตำแหน่งกระจกของช่องว่าง อัลกอริทึมต่อจากตำแหน่งนั้น
  2. ครบรอบแล้ว
    เมื่อเป้าหมายกลับไปที่ตำแหน่งเริ่มต้นเริ่มต้นของวัฏจักรปัจจุบันจะต้องพบอักขระที่ไม่สลับตำแหน่งถัดไป (หรือมากกว่านั้นตัวอักขระที่ไม่สลับใด ๆ ) จะต้องพบ เมื่อต้องการทำสิ่งนี้ภายใต้ข้อ จำกัด ของหน่วยความจำคงที่การแลกเปลี่ยนทั้งหมดที่ทำขึ้นจนถึงจุดนี้จะถูกติดตามกลับ

หลังจากขั้นตอนนี้อักขระที่ไม่ใช่ช่องว่างแต่ละตัวถูกย้ายอย่างมากหนึ่งครั้ง เมื่อต้องการเสร็จสิ้นอักขระอวกาศทั้งหมดจะถูกสลับกับอักขระที่ตำแหน่งมิรเรอร์ของพวกเขาต้องการการดำเนินการกำหนดสองครั้งต่อหนึ่งช่องว่าง


ว้าวมันเยี่ยมมาก คุณช่วยอธิบายได้ไหมว่าทำไมการวางตัวละครไว้ที่ตำแหน่งกระจกของพื้นที่จึงให้คำตอบที่ถูก
justhalf

1
@ Niklas ฉันไม่คิดว่าเป็นไปได้ เนื่องจากต้องการย้อนรอยคุณต้องมีข้อมูลตำแหน่งพื้นที่ หากคุณแทนที่ข้อมูลนั้นคุณจะไม่สามารถย้อนรอยย้อนกลับได้
justhalf

1
ฉันทำการเปรียบเทียบกับอัลกอริทึมของฉันในคำตอบของฉันที่นี่: codegolf.stackexchange.com/a/26952/16337
justhalf

1
@justhalf ในสตริงสุดท้ายช่องว่างทั้งหมดจะอยู่ในตำแหน่งที่มิเรอร์ ดังนั้นเราสามารถใช้ตำแหน่งนี้อย่างปลอดภัยเพื่อเก็บตัวละครที่เข้ามาแทนที่พื้นที่และเปลี่ยนมันในตอนท้าย
primo

1
ทำได้ดี. ฉันมีความคิดคล้าย ๆ กัน แต่ไม่คิดว่าจะออกจากที่ว่างแล้วสะท้อนให้เห็น
IchBinKeinBaum

7

ทับทิมคะแนน 2

ในฐานะที่เป็นผู้เริ่มต้นเป็นอัลกอริทึมพื้นฐานมาก มันจะย้อนกลับสตริงทั้งหมดและจากนั้นกลับคำแต่ละคำในสตริงอีกครั้ง ในกรณีที่เลวร้ายที่สุด (หนึ่งคำแม้จำนวนตัวอักษร) คะแนนจะกลายเป็น 2

def revstring(s, a, b)
  while a<b
    h = s[a]
    s[a] = s[b]
    s[b] = h
    a += 1
    b -= 1
  end
  s
end

def revwords(s)
  revstring(s, 0, s.length-1)
  a = 0
  while a<s.length
    b = a+1
    b += 1 while b<s.length and s[b]!=" "
    revstring(s, a, b-1)
    a = b+1
  end
  s
end

การใช้งาน:

> revwords("hello there everyone")
"everyone there hello"

ทำไมคุณไม่ใช้ฟังก์ชันในตัวของ Ruby เพื่อย้อนกลับสตริง? มันจะเปลี่ยนคะแนนหรือไม่
อัล

ใช้, s [a], s [b] = s [b], s [a]
Thaha kp

5

C ++: คะแนน 2

#include<iostream>
#include<algorithm>

void rev(std::string& s)
{
    std::reverse(s.begin(),s.end());
    std::string::iterator i=s.begin(),j=s.begin();
    while(i!=s.end())
    {
        while(i!=s.end()&&(*i)==' ')
            i++;
        j=i;
        while(i!=s.end()&&(*i)!=' ')
            i++;
        std::reverse(j,i);
    }
}

int main()
{
    std::string s;
    getline(std::cin,s);
    rev(s);
    std::cout<<s;
}

2
ฉันทดสอบมัน ทำได้ดี!
bacchusbeale

2

REBOL

reverse-words: function [
    "Reverse the order of words. Modifies and returns string (series)"
    series [string!] "At position (modified)"
  ][
    first-time: on
    until [
        reverse/part series f: any [
            if first-time [tail series]
            find series space
            tail series
        ]
        unless first-time [series: next f]
        first-time: off
        tail? series
    ]

    series: head series
]

ฉันไม่ชัดเจนในการให้คะแนนสำหรับสิ่งนี้ ไม่มีการกำหนดสตริงโดยตรงในรหัสนี้ ทุกอย่างได้รับการจัดการโดยผู้reverse/partที่กลับเข้ามาแทนที่และเริ่มต้นจากสตริงทั้งหมด

รายละเอียดบางอย่างเกี่ยวกับรหัส:

  • วนผ่านสตริง (series ) จนกว่าจะถึงtail?

  • ครั้งแรกในวงวนจะย้อนกลับของสตริง - reverse/part series tail series (ซึ่งเหมือนกับreverse series)

  • จากนั้นกลับคำทุกคำที่พบในการวนซ้ำต่อไป - reverse/part series find series space

  • เมื่อพบคำที่หมดแล้วกลับมา tail seriesเพื่อที่มันจะกลับคำสุดท้ายในสตริง -reverse/part series tail series

Rebol อนุญาตให้ทำการเคลื่อนที่ของสตริงผ่านตัวชี้ภายในตัวชี้คุณสามารถดูได้ที่series: next f (เลื่อนตัวชี้ไปที่ช่องว่างเพื่อเริ่มต้นของคำถัดไป) และseries: head series(รีเซ็ตตัวชี้กลับไปที่หัว)

ดู ซีรี่ส์สำหรับข้อมูลเพิ่มเติม

ตัวอย่างการใช้งานในคอนโซล Rebol:

>> reverse-words "everyone there hello"
== "hello there everyone"

>> x: "world hello"
== "world hello"

>> reverse-words x
== "hello world"

>> x
== "hello world"

>> reverse-words "hello"
== "hello"

ในการผ่านครั้งแรกอักขระแต่ละตัวจะถูกเปลี่ยนตำแหน่งหนึ่งครั้งและในการผ่านครั้งที่สองอักขระที่ไม่ใช่ช่องว่างจะถูกปรับตำแหน่งอีกครั้ง สำหรับการป้อนข้อมูลขนาดใหญ่โดยพลการที่มีช่องว่างค่อนข้างน้อยคะแนนจะเข้าใกล้ 2
โม่

2

C: คะแนน 2

สิ่งนี้จะพลิกทั้งสตริงเพียงครั้งเดียวแล้วกลับคำแต่ละคำ

#include <stdio.h>
#include <string.h>

void reverse(char *s,unsigned n){
    char c;
    unsigned i=0,r=1;
    while(i < n){ //no swap function in C 
        c=s[i];
        s[i++]=s[n];
        s[n--]=c;
    }
}

unsigned wordlen(char *s){
    unsigned i=0;
    while (s[i] != ' ' && s[i]) ++i;
    return i;
}

int main(int argc, char **argv) {
    char buf[]="reverse this also";
    char *s=buf;
    unsigned wlen=0,len=strlen(s)-1;
    reverse(s,len);  //reverse entire string
    while(wlen<len){  // iterate over each word till end of string
      wlen=wordlen(s);
      reverse(s,wlen-1);
      s+=wlen+1;
      len-=wlen;
    }
    printf("%s\n",buf);
    return 0;
}

3
นี่เป็นคำตอบเฉพาะรหัสเท่านั้น ลองเพิ่มคำอธิบายว่าเกิดอะไรขึ้นในโค้ดของคุณ
Justin

1

Python: คะแนน 2

เกือบจะเหมือนกับอัลกอริธึมของฮาวเวิร์ด แต่ทำขั้นตอนการสลับด้านในสิ่งที่ตรงกันข้าม หน่วยความจำเพิ่มเติมที่ใช้คือ 3 ตัวแปรไบต์ขนาด: i, และj tเทคนิคfindและการlenใช้ตัวแปรภายในบางอย่าง แต่พวกเขาสามารถได้อย่างง่ายดายเพียงกลับมาใช้iหรือjโดยไม่ต้องสูญเสียการทำงานใด ๆ

การแก้ไขอย่างรวดเร็ว:บันทึกการกำหนดสตริงโดยการแลกเปลี่ยนเฉพาะเมื่อตัวละครแตกต่างกันดังนั้นฉันจึงสามารถคว้าคะแนนพิเศษบางส่วนจากหมายเหตุ # 2

from sys import stdin

def word_reverse(string):
    # reverse each word
    i=0
    j=string.find(' ')-1
    if j == -2: j=len(string)-1
    while True:
        while i<j:
            if string[i] != string[j]:
                t = string[i]
                string[i] = string[j]
                string[j] = t
            i,j = i+1,j-1
        i=string.find(' ', i)+1
        if i==0: break
        j=string.find(' ', i)-1
        if j == -2: j=len(string)-1
    # reverse the entire string
    i=0
    j=len(string)-1
    while i<j:
        if string[i] != string[j]:
            t = string[i]
            string[i] = string[j]
            string[j] = t
        i,j = i+1,j-1
    return string

for line in stdin.readlines():
    # http://stackoverflow.com/a/3463789/1935085
    line = line.strip() # no trailing newlines ore spaces to ensure it conforms to '[a-z]+( [a-z]+)*'
    print word_reverse(bytearray(line))

1

ชุด

ฉันจะยอมรับว่าไม่เข้าใจการให้คะแนนอย่างสมบูรณ์ (ฉันคิดว่ามันเป็นสอง) .. แต่ฉันจะบอกว่า - มันทำสิ่งนั้น

@echo off

setLocal enableDelayedExpansion
set c=
set s=

for %%a in (%~1) do set /a c+=1 & echo %%a >> f!c!

for /L %%a in (!c!, -1, 1) do (
    set /p t=<f%%a
    set s=!s!!t!
    del f%%a
)

echo !s!

อินพุตถูกใช้เป็นค่าอินพุตมาตรฐานแรกดังนั้นจำเป็นต้องล้อมรอบด้วยเครื่องหมายคำพูด - การ
โทร: script.bat "hello there everyone"
ออก:everyone there helloออก:

บางทีคนอื่นสามารถให้คะแนนฉัน (สมมติว่าฉันไม่ได้ตัดสิทธิ์ตัวเองด้วยวิธีอื่น)


-2

จาวาสคริ

function reverseWords(input) {
    if (input.match(/^[a-z]+( [a-z]+)*$/g)) {
        return input.split(' ').reverse().join(' ');
    }
}

การใช้งาน:

> reverseWords('hello there everyone');
'everyone there hello'

ฉันรู้สึกแปลก ๆ ที่ฉันพลาดบางอย่าง ...


3
ใช่นี่ไม่ได้อยู่ในสถานที่เพราะคุณไม่ได้แก้ไขสายป้อน เนื่องจากเป็นไปไม่ได้ใน JavaScript คุณต้องเลียนแบบสตริงด้วยอาร์เรย์อักขระ (เช่นจำนวนเต็มของรหัสจุดหรือสตริงอักขระเดี่ยว)
Martin Ender

ยิ่งไปกว่านั้นจะใช้พื้นที่เพิ่มเติมจำนวนมาก
Ben Millwood
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.