1. 程式人生 > >LeetCode93 Restore IP Addresses 還原ip地址 最快解法

LeetCode93 Restore IP Addresses 還原ip地址 最快解法

題目描述

Restore IP Addresses。 給定一個ip地址的字串,但字串中應該有的三個點被抹掉了,所以現在的字串裡面全是數字。要求是給定一個只有數字的字串,輸出該字串可能構成的ip地址。 樣例輸入: 25525511135 樣例輸出: [“255.255.11.135”, “255.255.111.35”]

思路

第一:分段合理性。將三個點插入到數字時,會形成四段ip,那麼每段ip的長度至少是1,至多是3。 第二:段內ip合理性。段內數字的範圍應為0-255範圍,而且除非這段ip的長度為1,那麼該段的ip的第一個數字就不能為‘0’。

其實一開始想肯定會想到用遞迴來分段,分段則是先分第一段,再分第二段,再分第三段,但是這樣必然會遞迴到很多分段不合理

的ip分段。下面我來闡述一下我的思路。

先考慮分段合理性。 設輸入字元長度為n,那麼數字的索引則為0 - n-1。 想象在每兩個數字之間有一個可以供點插入的位置,那麼這樣的位置有m = n-1個。點的索引為0 - m-1。 這裡寫圖片描述 以上圖為例,如果原數字只有4個位置,那麼三個點可以插入的位置只有3個,那麼分段就只有一種方案。 這裡寫圖片描述 以上圖為例,如果數字有0-10的索引,那麼點的位置則是0-9索引。現在的問題就變成了要從0-9索引中,挑選三個位置供點插入,使得插入後的ip分段達到分段合理性

1.相鄰兩個點的索引之差不能超過3(這裡也可以把左邊界和右邊界考慮進來作為相鄰),比如第一個點索引為0,第二個點索引為3,它們之間的數字就有3個了。如果點索引選0和4,那麼這個ip分段就不合理了。 2.考慮左右邊界,所以第一個點索引,最多到達2;第三個點最多到達7。不然分段內的數字就會超過3個了。

正式講解在這裡插入圖片描述 本文思路是:1.先考慮分段的每段長度的合理性 2.再考慮每段內的數字是否合理 考驗每段分段的長度是否合理,其實就是考慮如何插入三個點到點索引0 - m-1中去,使得每段分段的長度都是至少為1,至多為3的。 如上圖所示,考慮ip地址中的三個點的可插入位置的範圍,可以把點的索引分為三個部分。這裡我先確定第一個點的可插入範圍為i,再確定第三個點的可插入範圍為j,最後再確定第二個點的可插入。 為什麼是這麼一個順序呢,因為i的範圍最多是延伸到2,而j的範圍最多是延伸到m-3,而k的範圍則需要在ij範圍確定下來,才能確定下來。 按照這個思路,我們在ij合理地確定下來以後,我們唯一需要關心的就是k可不可以找到一個可以插入的位置? ij合理性是指,i從左最多到2,j從右最多到m-3,而且ij之間至少得有一個索引,不然k就沒有可以插入的位置。當然ij之間也不能離太遠,ij之間空出來的索引的總長度最多為5,這樣k當好可以插入到中間那個位置使得分出來的兩個分段的長度都是3。(這段話讀者可以在本文第二個圖上驗證,所以就有了min=1,max=5)。

1.首先是如何確定一個合理的ii從左邊界往右延伸最多到2,但由於還留兩個位置給jk,所以i最多到min(2,m-3)

2.利用min=1,max=5這個結論,我們開始進一步推理。現在假設已經確定一個合理的i,需要確定一個合理的j。所以剩下的範圍就只有i+1 - m-1中可以選一個j了。 在這裡插入圖片描述 利用ij之間的索引長度最多為5(max=5),所以j的最大值為i+6,但是往右延伸有邊界m-1,所以往右延伸的最大值為right=min(i+6,m-1) 在這裡插入圖片描述 利用第四段分段最長長度為3,所以j的最小值為m-3,但是往左延伸有邊界i+2(因為有min=1,即ij之間至少有一個空位),所以往左延伸的最大值為left=max(m-3,i+2)

只有當right>=left時,j才有可能有一個合理值。j的取值範圍為[left, right]。所以現在可以得到一個合理的j了。

3.現在已經有了一個合理的ij,現在只需要根據ij之間的空位個數,就可以知道合理的k是誰了。

  • 當空位個數為5即(j-i) == 6,那麼k只能取中間值,即(j+i)//2
  • 當空位個數為4即(j-i) == 5,那麼k只能取兩個值,即(j+i)//2(j+i)//2+1
  • 當1<=空位個數<=3即(j-i) <= 4,那麼k可以取多個值,即範圍[i+1, j-1],也就是ij間的所有空位

以上三個結論讀者可以通過本文第二個圖驗證。

之後再驗證4個分段內的數字是否合理就可以了。

程式碼

class Solution:

    def check(self,s , i , k , j):
        n = len(s)
        m = n-1

        li = [[0,i],[i+1,k],[k+1,j],[j+1,n-1]]
        #每個段的開始索引和結束索引
        flag = True
        resultli = []
        for start,end in li:
            #分片
            temp = s[start:end+1]
            if (temp[0] == '0') and len(temp)!=1:
                flag = False
                break
            value = int(temp)
            if (value <0) or (value>255):
                flag = False
                break
            resultli.append(temp)
        if flag == True:
            return '.'.join(resultli)
        else:
            return False

    def restoreIpAddresses(self, s):
        """
        :type s: str
        :rtype: List[str]
        """
        #邊界條件

        #非邊界條件
        n = len(s)
        m = n-1#點可選位置的索引最大值

        li = []
        for i in range(min(2,m-3)+1):#向右最多延伸到2,但還得至少留兩個位置給jk
            #確定下來了左邊的點

            right=min(i+6,m-1)
            left=max(m-3,i+2)
  
            if(right >= left):
                
                for j in range(left,right+1):
                    #確定下來了右邊的點
                    if (j-i) <= 4:
                        for k in range(i+1,j):
                            result = self.check(s , i , k , j)
                            if result != False:
                                li.append(result)
                    elif (j-i) == 5:
                        middle = (j+i)//2
                        for k in range(middle,middle+2):
                            result = self.check(s , i , k , j)
                            if result != False:
                                li.append(result)
                    elif (j-i) == 6:
                        middle = (j+i)//2
                        result = self.check(s , i , middle , j)
                        if result != False:
                            li.append(result)
        return li

多次在LeetCode上面提交,執行時間40ms。