Given a start IP address ip and a number of ips we need to cover n, return a representation of the range as a list (of smallest possible length) of CIDR blocks.
A CIDR block is a string consisting of an IP, followed by a slash, and then the prefix length. For example: "123.45.67.89/20". That prefix length "20" represents the number of common prefix bits in the specified range.
Example 1:
Input: ip = "255.0.0.7", n = 10 Output: ["255.0.0.7/32","255.0.0.8/29","255.0.0.16/32"] Explanation: The initial ip address, when converted to binary, looks like this (spaces added for clarity): 255.0.0.7 -> 11111111 00000000 00000000 00000111 The address "255.0.0.7/32" specifies all addresses with a common prefix of 32 bits to the given address, ie. just this one address. The address "255.0.0.8/29" specifies all addresses with a common prefix of 29 bits to the given address: 255.0.0.8 -> 11111111 00000000 00000000 00001000 Addresses with common prefix of 29 bits are: 11111111 00000000 00000000 00001000 11111111 00000000 00000000 00001001 11111111 00000000 00000000 00001010 11111111 00000000 00000000 00001011 11111111 00000000 00000000 00001100 11111111 00000000 00000000 00001101 11111111 00000000 00000000 00001110 11111111 00000000 00000000 00001111 The address "255.0.0.16/32" specifies all addresses with a common prefix of 32 bits to the given address, ie. just 11111111 00000000 00000000 00010000. In total, the answer specifies the range of 10 ips starting with the address 255.0.0.7 . There were other representations, such as: ["255.0.0.7/32","255.0.0.8/30", "255.0.0.12/30", "255.0.0.16/32"], but our answer was the shortest possible. Also note that a representation beginning with say, "255.0.0.7/30" would be incorrect, because it includes addresses like 255.0.0.4 = 11111111 00000000 00000000 00000100 that are outside the specified range.
Note:
ipwill be a valid IPv4 address.- Every implied address
ip + x(forx < n) will be a valid IPv4 address. nwill be an integer in the range[1, 1000].
這道題博主剛開始做的時候,看了半天,讀不懂題目的意思,結果一看是一道Easy的題,直接???尼克楊問號臉???后來通過研究論壇上大家的解法,才總算明白了這道題讓我們做什么。此題給了我們一個用字符串表示的ip地址,還有一個整數n,讓我們以給定的ip地址為起點,需要覆蓋n個ip地址。而這n個ip地址的寫法使用無類別域間路由CIDR塊來寫,所謂的CIDR塊,是由一個正常的ip地址,加上斜杠數字,斜杠后面的數字表示這些ip地址具有相同的前綴的個數,比如"255.0.0.7/32",如果有32個相同的前綴,說明只有唯一的一個ip地址,因為IPv4總共就只有32位。再比如"255.0.0.8/29",表示有29個相同的前綴,那么最后3位可以自由發揮,2的3次方為8,所以就共有8個ip地址。同理,"255.0.0.16/32"只表示一個地址,那么這三個CIDR塊總共覆蓋了10個地址,就是我們要求的結果。
由於題目中要求盡可能少的使用CIDR塊,那么在n確定的情況下,CIDR塊能覆蓋的越多越好。根據我們前面的分析,當CIDR塊斜杠后面的數字越小,該塊覆蓋的ip地址越多。那么就是說相同前綴的個數越少越好,但是我們的ip地址又不能小於給定的ip地址,所以我們只能將0變為1,而不能將1變為0。所以我們的選擇就是有將最低位1后面的0進行變換,比如"255.0.0.8"末尾有3個0,可以變換出8個不同的地址。那么我們只要找出末尾1的位置,就知道能覆蓋多少個地址了。找末尾1有個trick,就是利用 x & -x 來快速找到,這個trick在之前做的題中也有應用。知道了最多能覆蓋地址的數量,還要考慮到n的大小,不能超過n,因為題目只要求覆蓋n個。確定了覆蓋的個數,我們就可以進行生成CIDR塊的操作了,之前我們為了求 x & -x,將ip地址轉為了一個十進制的數,現在我們要把每一塊拆分出來,直接按對應位數量進行右移並與上255即可,斜杠后的數字計算通過覆蓋的個數進行log2運算,再被32減去即可,參見代碼如下:
class Solution { public: vector<string> ipToCIDR(string ip, int n) { vector<string> res; long x = 0; istringstream is(ip); string t; while (getline(is, t, '.')) { x = x * 256 + stoi(t); } while (n > 0) { long step = x & -x; while (step > n) step /= 2; res.push_back(convert(x, step)); x += step; n -= step; } return res; } string convert(long x, int step) { return to_string((x >> 24) & 255) + "." + to_string((x >> 16) & 255) + "." + to_string((x >> 8) & 255) + "." + to_string(x & 255) + "/" + to_string(32 - (int)log2(step)); } };
類似題目:
參考資料:
https://discuss.leetcode.com/topic/115127/10-lines-java-solution
https://discuss.leetcode.com/topic/114848/very-simple-java-solution-beat-100
