leetcode常規算法題復盤(第一期)——黑盒光線反射


題目原文:

LCP 27. 黑盒光線反射

秋日市集上有個奇怪的黑盒,黑盒的主視圖為 n*m 的矩形。從黑盒的主視圖來看,黑盒的上面和下面各均勻分布有 m 個小孔,黑盒的左面和右面各均勻分布有 n 個小孔。黑盒左上角小孔序號為 0,按順時針編號,總共有 2*(m+n) 個小孔。每個小孔均可以打開或者關閉,初始時,所有小孔均處於關閉狀態。每個小孔上的蓋子均為鏡面材質。例如一個 2*3 的黑盒主視圖與其小孔分布如圖所示:

image.png

店長告訴小扣,這里是「幾何學的快問快答」,店長可能有兩種操作:

  • open(int index, int direction) - 若小孔處於關閉狀態,則打開小孔,照入光線;否則直接照入光線;
  • close(int index) - 關閉處於打開狀態小孔,店長保證不會關閉已處於關閉狀態的小孔;

其中:

  • index: 表示小孔序號
  • direction1 表示光線沿 y=xy=xy=x 方向,-1 表示光線沿 y=−xy=-xy=x 方向。

image.png

當光線照至邊界時:若邊界上的小孔為開啟狀態,則光線會射出;否則,光線會在小孔之間進行反射。特別地:

  1. 若光線射向未打開的拐角(黑盒頂點),則光線會原路反射回去;
  2. 光線自拐角處的小孔照入時,只有一種入射方向(如自序號為 0 的小孔照入方向只能為 -1

image.png

請幫助小扣判斷並返回店長每次照入的光線從幾號小孔射出。

示例 1:

輸入:
["BlackBox","open","open","open","close","open"]
[[2,3],[6,-1],[4,-1],[0,-1],[6],[0,-1]]

輸出:[null,6,4,6,null,4]

解釋:
BlackBox b = BlackBox(2,3); // 新建一個 2x3 的黑盒
b.open(6,-1) // 打開 6 號小孔,並沿 y=-x 方向照入光線,光線至 0 號小孔反射,從 6 號小孔射出
b.open(4,-1) // 打開 4 號小孔,並沿 y=-x 方向照入光線,光線軌跡為 4-2-8-2-4,從 4 號小孔射出
b.open(0,-1) // 打開 0 號小孔,並沿 y=-x 方向照入光線,由於 6 號小孔為開啟狀態,光線從 6 號小孔射出
b.close(6) // 關閉 6 號小孔
b.shoot(0,-1) // 從 0 號小孔沿 y=-x 方向照入光線,由於 6 號小孔為關閉狀態,4 號小孔為開啟狀態,光線軌跡為 0-6-4,從 4 號小孔射出

示例 2:

輸入:
["BlackBox","open","open","open","open","close","open","close","open"]
[[3,3],[1,-1],[5,1],[11,-1],[11,1],[1],[11,1],[5],[11,-1]]

輸出:[null,1,1,5,1,null,5,null,11]

解釋:

image.png

BlackBox b = BlackBox(3,3); // 新建一個 3x3 的黑盒
b.open(1,-1) // 打開 1 號小孔,並沿 y=-x 方向照入光線,光線軌跡為 1-5-7-11-1,從 1 號小孔射出
b.open(5,1) // 打開 5 號小孔,並沿 y=x 方向照入光線,光線軌跡為 5-7-11-1,從 1 號小孔射出
b.open(11,-1) // 打開 11 號小孔,並沿逆 y=-x 方向照入光線,光線軌跡為 11-7-5,從 5 號小孔射出
b.open(11,1) // 從 11 號小孔沿 y=x 方向照入光線,光線軌跡為 11-1,從 1 號小孔射出
b.close(1) // 關閉 1 號小孔
b.open(11,1) // 從 11 號小孔沿 y=x 方向照入光線,光線軌跡為 11-1-5,從 5 號小孔射出
b.close(5) // 關閉 5 號小孔
b.open(11,-1) // 從 11 號小孔沿 y=-x 方向照入光線,光線軌跡為 11-1-5-7-11,從 11 號小孔射出

提示:

  • 1 <= n, m <= 10000
  • 1 <= 操作次數 <= 10000
  • direction 僅為 1-1
  • 0 <= index < 2*(m+n)

 嘗試解答:

 先上我自己的代碼:

  1 class BlackBox(object):
  2 
  3     def __init__(self, n, m):
  4         """
  5         :type n: int
  6         :type m: int
  7         """
  8         self.m = m
  9         self.n = n
 10         self.pt_list = self.mkpoints()
 11         
 12         
 13     def open(self, index, direction):
 14         """
 15         :type index: int
 16         :type direction: int
 17         :rtype: int
 18         """
 19         
 20         self.pt_list[index]["state"] = "open"
 21         list_open = []
 22         list_close = []
 23         list_conner = []
 24         for dic in self.pt_list:
 25             if dic["state"] == "open":
 26                 list_open.append(dic["coord"])
 27             if dic["state"] == "close":
 28                 list_close.append(dic["coord"])
 29             if dic["location"] == "top_left" or dic["location"] == "top_right" or dic["location"] == "bottom_left" or dic["location"] == "bottom_right":
 30                 list_conner.append(dic["coord"])
 31         for dic in self.pt_list:
 32             if dic["id"] == index:
 33                 coord = dic["coord"]
 34         direction = direction
 35         out_coord = self.guangxian(coord,self.pt_list,direction,list_open,list_close,list_conner)
 36         
 37         for dic in self.pt_list:
 38             if dic["coord"] == out_coord:
 39             
 40                 return dic["id"]
 41 
 42     def close(self, index):
 43         """
 44         :type index: int'method' object is not subscriptable
 45         :rtype: None
 46         """
 47         self.pt_list[index]["state"] = "close"
 48         
 49         return None
 50 
 51 
 52 
 53     def mkpoints(self):
 54         n = self.n
 55         m = self.m
 56         sum = (n+m)*2
 57         pt_list = [] #創建一個列表用來存儲每個孔的字典
 58         for i in range(sum): #為每個孔創建字典
 59             pt_list.append(dict(id=i,state="close",coord=[0,0],location="top_left"))
 60         for dic in pt_list: #初始化每個孔的字典
 61             if dic["id"] == 0:
 62                 dic["location"] = "top_left"
 63                 dic["coord"] = [0,0]
 64             if dic["id"] == m:
 65                 dic["location"] = "top_right"
 66                 dic["coord"] = [0,m]
 67             if dic["id"] == m+n:
 68                 dic["location"] = "bottom_right"
 69                 dic["coord"] = [n,m]
 70             if dic["id"] == 2*m+n:
 71                 dic["location"] = "bottom_left"
 72                 dic["coord"] = [n,0]
 73             if dic["id"] > 0 and dic["id"] < m:
 74                 dic["location"] = "top"
 75                 dic["coord"] = [0,dic["id"]]
 76             if dic["id"] > m and dic["id"] < (m+n):
 77                 dic["location"] = "right"
 78                 dic["coord"] = [dic["id"]-m,m]
 79             if dic["id"] > (m+n) and dic["id"] < (2*m+n):
 80                 dic["location"] = "bottom"
 81                 dic["coord"] = [n,(2*m+n)-dic["id"]]
 82             if dic["id"] > (2*m+n) and dic["id"] < sum:
 83                 dic["location"] = "left"
 84                 dic["coord"] = [sum-dic["id"],0]
 85 
 86         return pt_list
 87     
 88     
 89     
 90     def guangxian(self,coord,pt_list,direction,list_open,list_close,list_conner):
 91         for dic in pt_list:
 92             if dic["coord"] == coord:
 93                 index = dic["id"]
 94                 location = dic["location"]
 95         if direction == 1:
 96             if location == "top":
 97                 while(True):
 98                     coord = [coord[0]+1,coord[1]-1]
 99                     #print(coord)
100                     if coord in list_open:
101                         return coord
102                     if coord in list_close:
103                         if coord in list_conner:
104                             return self.guangxian(coord,pt_list,direction,list_open,list_close,list_conner)
105                         else:
106                             return self.guangxian(coord,pt_list,direction*(-1),list_open,list_close,list_conner)
107             if location == "bottom":
108                 while(True):
109                     coord = [coord[0]-1,coord[1]+1]
110                     #print(coord)
111                     if coord in list_open:
112                         return coord
113                     if coord in list_close:
114                         if coord in list_conner:
115                             return self.guangxian(coord,pt_list,direction,list_open,list_close,list_conner)
116                         else:
117                             return self.guangxian(coord,pt_list,direction*(-1),list_open,list_close,list_conner)
118             if location == "left":
119                 while(True):
120                     coord = [coord[0]-1,coord[1]+1]
121                     #print(coord)
122                     if coord in list_open:
123                         return coord
124                     if coord in list_close:
125                         if coord in list_conner:
126                             return self.guangxian(coord,pt_list,direction,list_open,list_close,list_conner)
127                         else:
128                             return self.guangxian(coord,pt_list,direction*(-1),list_open,list_close,list_conner)
129             if location == "right":
130                 while(True):
131                     coord = [coord[0]+1,coord[1]-1]
132                     #print(coord)
133                     if coord in list_open:
134                         return coord
135                     if coord in list_close:
136                         if coord in list_conner:
137                             return self.guangxian(coord,pt_list,direction,list_open,list_close,list_conner)
138                         else:
139                             return self.guangxian(coord,pt_list,direction*(-1),list_open,list_close,list_conner)
140             if location == "top_right":
141                 while(True):
142                     coord = [coord[0]+1,coord[1]-1]
143                     #print(coord)
144                     if coord in list_open:
145                         return coord
146                     if coord in list_close:
147                         if coord in list_conner:
148                             return self.guangxian(coord,pt_list,direction,list_open,list_close,list_conner)
149                         else:
150                             return self.guangxian(coord,pt_list,direction*(-1),list_open,list_close,list_conner)
151             if location == "bottom_left":
152                 while(True):
153                     coord = [coord[0]-1,coord[1]+1]
154                     #print(coord)
155                     if coord in list_open:
156                         return coord
157                     if coord in list_close:
158                         if coord in list_conner:
159                             return self.guangxian(coord,pt_list,direction,list_open,list_close,list_conner)
160                         else:
161                             return self.guangxian(coord,pt_list,direction*(-1),list_open,list_close,list_conner)
162         if direction == -1:
163             if location == "top":
164                 while(True):
165                     coord = [coord[0]+1,coord[1]+1]
166                     #print(coord)
167                     if coord in list_open:
168                         return coord
169                     if coord in list_close:
170                         if coord in list_conner:
171                             return self.guangxian(coord,pt_list,direction,list_open,list_close,list_conner)
172                         else:
173                             return self.guangxian(coord,pt_list,direction*(-1),list_open,list_close,list_conner)
174             if location == "bottom":
175                 while(True):
176                     coord = [coord[0]-1,coord[1]-1]
177                     #print(coord)
178                     if coord in list_open:
179                         return coord
180                     if coord in list_close:
181                         if coord in list_conner:
182                             return self.guangxian(coord,pt_list,direction,list_open,list_close,list_conner)
183                         else:
184                             return self.guangxian(coord,pt_list,direction*(-1),list_open,list_close,list_conner)
185             if location == "left":
186                 while(True):
187                     coord = [coord[0]+1,coord[1]+1]
188                     #print(coord)
189                     if coord in list_open:
190                         return coord
191                     if coord in list_close:
192                         if coord in list_conner:
193                             return self.guangxian(coord,pt_list,direction,list_open,list_close,list_conner)
194                         else:
195                             return self.guangxian(coord,pt_list,direction*(-1),list_open,list_close,list_conner)
196             if location == "right":
197                 while(True):
198                     coord = [coord[0]-1,coord[1]-1]
199                     #print(coord)
200                     if coord in list_open:
201                         return coord
202                     if coord in list_close:
203                         if coord in list_conner:
204                             return self.guangxian(coord,pt_list,direction,list_open,list_close,list_conner)
205                         else:
206                             return self.guangxian(coord,pt_list,direction*(-1),list_open,list_close,list_conner)
207             if location == "top_left":
208                 while(True):
209                     coord = [coord[0]+1,coord[1]+1]
210                     #print(coord)
211                     if coord in list_open:
212                         return coord
213                     if coord in list_close:
214                         if coord in list_conner:
215                             return self.guangxian(coord,pt_list,direction,list_open,list_close,list_conner)
216                         else:
217                             return self.guangxian(coord,pt_list,direction*(-1),list_open,list_close,list_conner)
218             if location == "bottom_right":
219                 while(True):
220                     coord = [coord[0]-1,coord[1]-1]
221                     #print(coord)
222                     if coord in list_open:
223                         return coord
224                     if coord in list_close:
225                         if coord in list_conner:
226                             return self.guangxian(coord,pt_list,direction,list_open,list_close,list_conner)
227                         else:
228                             return self.guangxian(coord,pt_list,direction*(-1),list_open,list_close,list_conner)
229                 
230 
231 # Your BlackBox object will be instantiated and called as such:
232 # obj = BlackBox(n, m)
233 # param_1 = obj.open(index,direction)
234 # obj.close(index)

思路十分簡單無腦(意料之中的,運行短例子正確,運行超長例子時超時了),算法的設計非常欠考慮,也帶來了相應的代價,導致編碼時間過長、bug出現的可能性增加。黑盒被定義后,首先確定每個孔的狀態,將每個孔的狀態保存在一個字典中再將所有字典保存在一串列表中,其中小孔的狀態包括index、開閉狀態、在盒子中的方位(上下左右四角)、坐標,每次小孔的狀態變化,都會先查詢這個列表,在字典上進行修改,這其實是一個很大的問題,造成很高的空間復雜度,因此我的代碼無法在更大的“盒子”上運行,之后就是常規的遞歸算法,使guangxian在盒子的孔之間傳播,每傳播一次檢驗一次孔的狀態,並判斷下一個傳播方向。依次遞歸。

這里因為python語法基礎掌握不牢犯了三個低級錯誤:

一、類函數自我遞歸的時候沒有在函數開頭加self.,這里應該記住類函數自我遞歸的時候算作定義類內的同類間函數調用,因此應該在函數開頭加self.,而不應該在參數中加self(例:function(self,x),只有在類內定義函數的時候才會這么寫)。

二、遞歸的函數忘記return(好蠢),導致遞歸過程根本停不下來,浪費了許多時間來找問題所在。

三、忘記定義類內部靜態變量,導致pt_list無法常駐,只存在函數中的內部變量無法實現某些特定功能,下次記住。

標准題解:

思路一:

上大佬的代碼:

  1 import bisect
  2 
  3 
  4 class TreeSet(object):
  5     """
  6     Binary-tree set like java Treeset.
  7     Duplicate elements will not be added.
  8     When added new element, TreeSet will be sorted automatically.
  9     """
 10     def __init__(self, elements):
 11         self._treeset = []
 12         self.addAll(elements)
 13 
 14     def addAll(self, elements):
 15         for element in elements:
 16             if element in self: continue
 17             self.add(element)
 18 
 19     def add(self, element):
 20         if element not in self:
 21             bisect.insort(self._treeset, element)
 22 
 23     def ceiling_index(self, e, exclusive=False):
 24         index = bisect.bisect_right(self._treeset, e)
 25         if exclusive:
 26             return index
 27         if index > 0 and self[index - 1] == e:
 28             return index - 1
 29         return index
 30 
 31     def floor_index(self, e, exclusive=False):
 32         index = bisect.bisect_left(self._treeset, e)
 33         if exclusive:
 34             return index - 1
 35         if index < len(self) and self[index] == e:
 36             return index
 37         return index - 1
 38 
 39     def ceiling(self, e, exclusive=False):
 40         index = self.ceiling_index(e, exclusive)
 41         if 0 <= index < len(self):
 42             return self[index]
 43         return None
 44 
 45     def floor(self, e, exclusive=False):
 46         index = self.floor_index(e, exclusive)
 47         if 0 <= index < len(self):
 48             return self[index]
 49         return None
 50 
 51     def __getitem__(self, num):
 52         return self._treeset[num]
 53 
 54     def __len__(self):
 55         return len(self._treeset)
 56 
 57     def clear(self):
 58         """
 59         Delete all elements in TreeSet.
 60         """
 61         self._treeset = []
 62 
 63     def clone(self):
 64         """
 65         Return shallow copy of self.
 66         """
 67         return TreeSet(self._treeset)
 68 
 69     def remove(self, element):
 70         """
 71         Remove element if element in TreeSet.
 72         """
 73         try:
 74             self._treeset.remove(element)
 75         except ValueError:
 76             return False
 77         return True
 78 
 79     def __iter__(self):
 80         """
 81         Do ascending iteration for TreeSet
 82         """
 83         for element in self._treeset:
 84             yield element
 85 
 86     def pop(self, index):
 87         return self._treeset.pop(index)
 88 
 89     def __str__(self):
 90         return str(self._treeset)
 91 
 92     def __eq__(self, target):
 93         if isinstance(target, TreeSet):
 94             return self._treeset == target.treeset
 95         elif isinstance(target, list):
 96             return self._treeset == target
 97 
 98     def __contains__(self, e):
 99         """
100         Fast attribution judgment by bisect
101         """
102         try:
103             return e == self._treeset[bisect.bisect_left(self._treeset, e)]
104         except:
105             return False
106 
107 
108 class TreeMap(dict):
109     """
110     "TreeMap" is a dictionary with sorted keys similar to java TreeMap.
111     Keys, iteration, items, values will all return values ordered by key.
112     Otherwise it should behave just like the builtin dict.
113     """
114 
115     def __init__(self, seq=None, **kwargs):
116         if seq is None:
117             super().__init__(**kwargs)
118         else:
119             super().__init__(seq, **kwargs)
120         self.sorted_keys = TreeSet(super().keys())
121 
122     def __setitem__(self, key, value):
123         super().__setitem__(key, value)
124         self.sorted_keys.add(key)
125 
126     def __delitem__(self, key):
127         super().__delitem__(key)
128         self.sorted_keys.remove(key)
129 
130     def keys(self):
131         return self.sorted_keys
132 
133     def items(self):
134         return [(k, self[k]) for k in self.sorted_keys]
135 
136     def __iter__(self):
137         for k in self.sorted_keys:
138             yield k
139 
140     def values(self):
141         for k in self.sorted_keys:
142             yield self[k]
143 
144     def clear(self):
145         super().clear()
146         self.sorted_keys.clear()
147 
148     def ceiling_index(self, e, exclusive=False):
149         return self.sorted_keys.ceiling_index(e, exclusive)
150 
151     def floor_index(self, e, exclusive=False):
152         return self.sorted_keys.floor_index(e, exclusive)
153 
154     def ceiling_key(self, e, exclusive=False):
155         return self.sorted_keys.ceiling(e, exclusive)
156 
157     def floor_key(self, e, exclusive=False):
158         return self.sorted_keys.floor(e, exclusive)
159 
160     def ceiling_value(self, e, exclusive=False):
161         key = self.ceiling_key(e, exclusive)
162         return self[key] if key is not None else None
163 
164     def floor_value(self, e, exclusive=False):
165         key = self.floor_key(e, exclusive)
166         return self[key] if key is not None else None
167 
168 
169 class BlackBox:
170 
171     def __init__(self, n: int, m: int):
172         self.groupPos, self.groupNeg, self.groupStats = [], [], []
173         ptCount = (n + m) * 2
174         self.groupPos, self.groupNeg = [(-1, -1) for _ in range(ptCount)], [(-1, -1) for _ in range(ptCount)]
175         for i in range(ptCount):
176             # 如果不是左上角或者右下角的小孔,那么從 y=x 方向射出找循環
177             if i != 0 and i != m + n and self.groupPos[i][0] == -1:
178                 self.createGroup(n, m, i, 1)
179             # 如果不是左下角或者右上角的小孔,那么從 y=-x 方向射出找循環
180             if i != m and i != m * 2 + n and self.groupNeg[i][0] == -1:
181                 self.createGroup(n, m, i, -1)
182 
183     def createGroup(self, n: int, m: int, index: int, direction: int):
184         groupId = len(self.groupStats)
185         groupLoc = 0
186         self.groupStats.append(TreeMap())
187         # 不斷模擬光線的路徑,直到走到一個已經遇見過的狀態,這樣就找到了一個循環
188         while not (direction == 1 and self.groupPos[index][0] != -1) and not (direction == -1 and self.groupNeg[index][0] != -1):
189             if direction == 1:
190                 self.groupPos[index] = (groupId, groupLoc)
191                 index = (n + m) * 2 - index
192             else:
193                 self.groupNeg[index] = (groupId, groupLoc)
194                 index = m * 2 - index if index <= m * 2 else (m * 2 + n) * 2 - index
195             # 如果小孔不在角上,就改變方向
196             if index != 0 and index != m and index != m + n and index != m * 2 + n:
197                 direction = -direction
198             groupLoc += 1
199 
200     def open(self, index: int, direction: int) -> int:
201         # 插入二元組
202         groupId, groupLoc = self.groupPos[index]
203         if groupId != -1:
204             self.groupStats[groupId][groupLoc] = index
205         groupId, groupLoc = self.groupNeg[index]
206         if groupId != -1:
207             self.groupStats[groupId][groupLoc] = index
208 
209         # 查詢
210         groupId, groupLoc = self.groupPos[index] if direction == 1 else self.groupNeg[index]
211         store = self.groupStats[groupId]
212         ceiling = store.ceiling_value(groupLoc, exclusive=True)
213         if ceiling:
214             return ceiling
215         return store[store.keys()[0]]
216 
217     def close(self, index: int) -> None:
218         # 刪除二元組
219         groupId, groupLoc = self.groupPos[index]
220         if groupId != -1:
221             del self.groupStats[groupId][groupLoc]
222         groupId, groupLoc = self.groupNeg[index]
223         if groupId != -1:
224             del self.groupStats[groupId][groupLoc]
225 
226 
227 ##作者:acst
228 ##鏈接:https://leetcode-cn.com/problems/IQvJ9i/solution/yu-chu-li-chu-suo-you-de-xun-huan-_python3ban-ben-/
229 ##來源:力扣(LeetCode)
230 ##著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。

預處理出所有的循環_Python3版本

acst 發布於 2020-09-2296Python3

@zerotrac2大佬的解法譯成了Python3的代碼。

由於Python沒有如C++和Java方便的TreeSet和TreeMap庫。因此只能自己造輪子。。這里在https://github.com/fukatani/TreeSet代碼的基礎上進行了一些修改,做了Python3的TreeSet和TreeMap類。改進后的這兩個類也可以直接使用https://github.com/acst1223/always_code/tree/master/python中treeset.pytreemap.py的代碼

@apoi2333提醒,Python有Sorted Containers這個庫可以用,大家也可以去了解一下~

我自己的代碼(輪子)如下,前面的大段代碼均為TreeSet和TreeMap類內容。

知識擴充——bisect:

一個有趣的python排序模塊:bisect

今天同事說到了一個python的排序模塊bisect,覺得挺有趣的,跟大家分享分享。

       先看看模塊的結構:

      

       前面五個屬性大家感興趣可以打出來看看數值,這里就不介紹了。

       先說明的是,使用這個模塊的函數前先確保操作的列表是已排序的。

      

       先看看 insort  函數:

       

       其插入的結果是不會影響原有的排序。

       再看看 bisect  函數:

       

       其目的在於查找該數值將會插入的位置並返回,而不會插入。

       接着看 bisect_left 和 bisect_right 函數,該函數用入處理將會插入重復數值的情況,返回將會插入的位置:

       

       其對應的插入函數是 insort_left  和 insort_right :

       

       可見,單純看其結果的話,兩個函數的操作結果是一樣的,其實插入的位置不同而已。

 

 

 

 

 思路二:

 紅黑樹解法,先上大佬的代碼:

  1 const int N=1E5;
  2 int n, m;
  3 int index2map[N];
  4 int index2cmp_val[N];
  5 int map_allo = 0;
  6 
  7 struct comps {
  8     bool operator()(int i, int j) const{
  9         return index2cmp_val[i] < index2cmp_val[j];
 10     }
 11 };
 12 
 13 map<int, int, comps> maps[N];//1E5
 14 
 15 class BlackBox {
 16 public:
 17 
 18     inline int trans(int i, int k) {
 19         return i * 2 + (k == -1 ? 0 : 1);
 20     }
 21 
 22     inline int corner(int x) {
 23         return x == 0 || x == m - 1 || x == m + n - 1 || x == 2 * m + n - 1;
 24     }
 25 
 26     inline int getside(int x) {
 27         if (x < m)return 0;
 28         if (x < m + n)return 1;
 29         if (x < 2 * m + n)return 2;
 30         return 3;
 31     }
 32 
 33 
 34     int get_next(int x) {
 35         int pos = x / 2;
 36         int k = x % 2 ? 1 : -1;
 37         int s = getside(pos);
 38         int d = 0;
 39         if (s == 0) {
 40             if (k == 1) {
 41                 d = 2 * (m - pos);
 42             } else {
 43                 d = -2 * (pos);
 44             }
 45 
 46         } else if (s == 1) {
 47             if (k == 1) {
 48                 d = -2 * (pos - m);
 49             } else {
 50                 d = 2 * (m + n - pos);
 51             }
 52         } else if (s == 2) {
 53             if (k == 1) {
 54                 d = 2 * (2 * m + n - pos);
 55             } else {
 56                 d = -2 * (pos - m - n);
 57             }
 58         } else {
 59             if (k == 1) {
 60                 d = -2 * (pos - 2 * m - n);
 61             } else {
 62                 d = 2 * (2 * m + 2 * n - pos);
 63             }
 64         }
 65         return trans((pos + d + 2 * m + 2 * n) % (2 * m + 2 * n), -1 * k);
 66     }
 67 
 68     BlackBox(int nn, int mm) {
 69         memset(index2map,0,sizeof index2map);
 70         memset(index2cmp_val,0,sizeof index2cmp_val);
 71         n = nn;
 72         m = mm;
 73         for (int i = 0; i < 4 * m + 4 * n; i++) {
 74             if (index2map[i])continue;
 75             map_allo++;
 76             maps[map_allo].clear();
 77             int temp = i;
 78             int val = 1;
 79             while (1) {
 80                 index2map[temp] = map_allo;
 81                 index2cmp_val[temp] = val++;
 82                 temp = get_next(temp);
 83                 if (temp == i)break;
 84             }
 85         }
 86 
 87 
 88     }
 89 
 90     int open(int index, int direction) {
 91         int temp1 = trans(index, -direction);
 92         int temp2 = trans(index, direction);
 93         maps[index2map[temp1]][temp1] = 1;
 94         maps[index2map[temp2]][temp2] = 1;
 95 
 96         auto it = maps[index2map[temp1]].upper_bound(temp1);
 97         if (it == maps[index2map[temp1]].end()) {
 98             return maps[index2map[temp1]].begin()->first/2;
 99         }
100         return it->first/2;
101     }
102 
103     void close(int index) {
104         int temp1 = trans(index, 1);
105         int temp2 = trans(index, -1);
106         maps[index2map[temp1]].erase(temp1);
107         maps[index2map[temp2]].erase(temp2);
108     }
109 };
110 
111 
112 //作者:levyjeng
113 //鏈接:https://leetcode-cn.com/problems/IQvJ9i/solution/hong-hei-shu-jie-fa-by-levyjeng/
114 //來源:力扣(LeetCode)
115 //著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。

主要就是在預處理階段找出所有的反射循環,每個循環都存在一個紅黑樹里面,open的時候,就往該紅黑樹里面添加該位置並找出距離該位置最近的那個開放位置,而close的時候,就在相應的紅黑樹里面移除掉該位置
知識擴充——紅黑樹:
詳見印象筆記:https://app.yinxiang.com/fx/382ee9f5-7a1e-4b97-a2b8-73cd11ad1eaa

 

 

 

思路差距:

 一、理解題目完后就犯了一個很大的錯誤,沒有對模型進行更深入的解析,只能停留在表面的物理模型,導致計算復雜度爆炸,下次接觸類似算法題目時應該透過現象看本質,在物理層面下提煉其數字邏輯上的關系

二、這也是創建本博客的初衷,就是希望把刷題的效果最大化,刷題可以提高能力,“刷”的本身只占很小一部分,它提高的部分在於你的調用思維的速度,編碼速度,編程語言的熟練度,但是也不能直接跳過刷的部分,就算花掉許多時間也一定要把自己的思路完成實現,不然永遠不能讓思路成熟。而真正提高的部分在於刷完的“分析”,這其中包括找到自己容易犯的錯誤,找到自己的思維、技術漏洞、與大佬的差距,分析的過程也是學習、模仿的過程。切忌浮於表面!(雖然這一條就很浮於表面(x))

三、思路一、思路二的都是對反射規律進行了提煉,從一般性的光線反射問題提煉出了一套數字模型,即雙向的循環結構,並結合雙向的循環結構巧妙地套用了樹形數據結構,區別之處在於思路一構造了樹形排序、類似字典檢索的數據結構,思路二直接套用紅黑樹。

 

技術差距:

 一、反觀自己寫的代碼,可以發現它過於冗長,有大段的重復,這不是一個好現象,這是算法設計不好導致的,而且代碼的結構、函數的參數也沒經過事先的設計,這拖慢了編碼速度,下次在構思完算法思路后對代碼結構進行設計。

二、python語言應用不夠成熟,語句都是生硬的固定語法,離靈活運用還有不少的差距,需要在大量練習中進步。在類定義構建、類實體化等操作中還會犯低級語法、思路錯誤,這是數據結構、python語言機理等方面掌握不牢固導致的,還需要大量練習。

三、過多數量的多重遍歷,或者說過於依賴多重遍歷,榨干了機能(x)(平時看了不少cv代碼,導致不看重遍歷的優化,這句話冒犯cv工程師了嗎hhhhh),嚴重降低了代碼的性能,應該考慮優化其中的某些遍歷,將其去掉或者進行改良。

四、思路一中的代碼結構設計,作者是將另外一位大佬的C++改編成了python,改編帶來的問題就是,python沒有現成的數據結構,於是着手造了一個樹形排序結構、一個繼承字典查詢結構,后接一個黑盒類,代碼精煉清晰,類專有方法調用、重寫、應用如數家珍,足以看出python基礎扎實,代碼功力深厚(力扣題解不是隨隨便便就敢往上放的,BATH牛人數不勝數),這里也能看出我的差距,對數據結構、python基礎方法、專有方法生疏到令人發指,再不惡補鐵定要被遠遠甩后面~

五、思路二由C++實現,我看不太懂(菜雞本雞),大致是先確定每個孔的方位(上下左右分別用0、1、2、3表示),然后推動光線“傳播”,當然這個傳播是經過預處理模型簡化的,傳播進入循環階段后就沿用紅黑樹查詢節點重復狀態。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM