1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| class Solution { public int[] platesBetweenCandles(String s, int[][] queries) { char[] sArray = s.toCharArray(); int[] prevCandlePos = new int[s.length()]; int[] nextCandlePos = new int[s.length()]; int[] candleCount = new int[sArray.length]; int lastLeftCandle = -1, lastRightCandle = sArray.length, count = 0; for (int left = 0, right = sArray.length - 1; left < sArray.length; left++, right--) { if (sArray[left] == '*') { prevCandlePos[left] = lastLeftCandle; } else { lastLeftCandle = left; prevCandlePos[left] = left; count += 1; candleCount[left] = count; } if (sArray[right] == '*') { nextCandlePos[right] = lastRightCandle; } else { lastRightCandle = right; nextCandlePos[right] = right; } } int[] ans = new int[queries.length]; for (int i = 0; i < ans.length; i++) { int leftBound = queries[i][0]; int rightBound = queries[i][1]; int firstCandle = nextCandlePos[leftBound]; int lastCandle = prevCandlePos[rightBound]; if (firstCandle == -1 || lastCandle == -1) { ans[i] = 0; } else { int eleNum = lastCandle - firstCandle - 1; if (eleNum > 0) { ans[i] = eleNum - (candleCount[lastCandle] - candleCount[firstCandle] - 1); } else { ans[i] = 0; } } } return ans; } }
|
一开始想到了先计算每个plate的prev和next candle的位置. 但是没有想到在一个range中如何计算valid plates的个数. 想到了prefix sum但是没想到prefix记录的是candles的个数而非plates的个数, 因为如果记录plates的个数, 每个plate是否valid要看给的范围, 如何确定范围就是问题. 因此我们可以记录candles的个数的prefix sum. 在某个范围内candles的个数就能知道.
时间复杂度: O(N + Q)
空间复杂度: O(N + Q) N是存prev, next以及candleCount, Q是ans的长度.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| class Solution { public int[] platesBetweenCandles(String s, int[][] queries) { List<Integer> candleIdx = new ArrayList<>(); char[] sArray = s.toCharArray(); for (int i = 0; i < sArray.length; i++) { if (sArray[i] == '|') { candleIdx.add(i); } } int[] ans = new int[queries.length]; for (int i = 0; i < queries.length; i++) { int leftBound = queries[i][0]; int rightBound = queries[i][1]; int firstCandle = binarySearchCeil(candleIdx, leftBound); int lastCandle = binarySearchFloor(candleIdx, rightBound); if (firstCandle < lastCandle) { ans[i] = candleIdx.get(lastCandle) - candleIdx.get(firstCandle) + 1 - (lastCandle - firstCandle + 1); } else { ans[i] = 0; } } return ans; }
private int binarySearchCeil(List<Integer> candleIdx, int target) { int left = 0, right = candleIdx.size() - 1, ans = candleIdx.size(); while (left <= right) { int mid = left + (right - left) / 2; if (candleIdx.get(mid) > target) { ans = mid; right = mid - 1; } else if (candleIdx.get(mid) < target) { left = mid + 1; } else { ans = mid; break; } } return ans; }
private int binarySearchFloor(List<Integer> candleIdx, int target) { int left = 0, right = candleIdx.size() - 1, ans = -1; while (left <= right) { int mid = left + (right - left) / 2; if (candleIdx.get(mid) < target) { ans = mid; left = mid + 1; } else if (candleIdx.get(mid) > target) { right = mid - 1; } else { ans = mid; break; } } return ans; } }
|
这个是binary search的做法. 这个做法是真没想到. 我们记录每一个candle的index是什么. 当给我们一个range后, 我们计算这个range中第一个candle和最后一个candle的位置是什么. 找candle的位置就是binary search了, 我们需要找candle index比leftBound大的中最小的, candle index比rightBound小的中最大的. 找到后返回给我们的是这两个candle index在list中的index, 实际在s中的index需要list.get()一下, 毕竟我们在list中记录的就是candle在s中的index. 之后我们计算这两个candle框起来的区域长度是多少, 然后这个区域内candle的数量是多少.
时间复杂度: O(N + 2QlogN) 我们准备candle的list是O(N), list中candle的个数最多是N个, 我们需要进行2Q次binary search(一个floor, 一个ceil). 因此是O(N + QlogN)
空间复杂度: O(N) 我们需要存candle的index都是什么.