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’。
其實一開始想肯定會想到用遞迴來分段,分段則是先分第一段,再分第二段,再分第三段,但是這樣必然會遞迴到很多分段不合理
先考慮分段合理性。 設輸入字元長度為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.首先是如何確定一個合理的i
,i
從左邊界往右延伸最多到2,但由於還留兩個位置給j
和k
,所以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,即i
與j
之間至少有一個空位),所以往左延伸的最大值為left=max(m-3,i+2)
只有當right
>=left
時,j
才有可能有一個合理值。j
的取值範圍為[left, right]
。所以現在可以得到一個合理的j
了。
3.現在已經有了一個合理的i
和j
,現在只需要根據i
和j
之間的空位個數,就可以知道合理的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。