有一个数据流,设计一种数据结构,在任意时刻,找到其中的中位数。
1.用两堆的实现方法
static class MedianFinder {
PriorityQueue<Integer> minHeap;
PriorityQueue<Integer> maxHeap;
public MedianFinder() {
minHeap = new PriorityQueue<>();
maxHeap = new PriorityQueue<>(Collections.reverseOrder());
}
public void addNum(int num) {
// maxHeap.add(num);
// minHeap.add(maxHeap.poll());
// if (minHeap.size() > maxHeap.size()) {
// maxHeap.add(minHeap.poll());
// }
if (maxHeap.isEmpty() || maxHeap.peek() > num)
maxHeap.offer(num);
else
minHeap.offer(num);
// 使两堆元素平衡 奇数时maxHeap多1个
if (minHeap.size() > maxHeap.size()) {
maxHeap.offer(minHeap.poll());
} else if (maxHeap.size() - minHeap.size() >= 2) {
minHeap.offer(maxHeap.poll());
}
}
public double findMedian() {
if (maxHeap.size() == minHeap.size())
return (maxHeap.peek() + minHeap.peek()) / 2.0;
else
return maxHeap.peek();
}
}
2.用Arraylist结合二分插入
class MedianFinder {
List<Integer> list;
public MedianFinder() {
list = new ArrayList<>();
}
public void addNum(int num) {
if (list.isEmpty() || list.size() > 0 && num > list.get(list.size() - 1)) {
list.add(num);
return;
}
int left = 0, right = list.size() - 1;
// 二分查找插入位置
while (left < right) {
int mid = left + (right - left) / 2;
int midVal = list.get(mid);
if (midVal < num)
left = mid + 1;
else
right = mid;
}
list.add(left, num);
}
public double findMedian() {
int size = list.size();
if (size % 2 == 1)
return list.get(size / 2);
return (list.get(size / 2) + list.get(size / 2 - 1)) / 2.0;
}
}
315 .计算右侧小于当前元素的个数
给定一个整数数组 nums,按要求返回一个新数组 counts。数组 counts 有该性质: counts[i] 的值是 nums[i] 右侧小于 nums[i] 的元素的数量。
示例:
输入: [5,2,6,1]
输出: [2,1,1,0]
思路:
从后往前二分查找nums[i]插入的位置,对应的index就是该数把多少元素压在底下
public static List<Integer> countSmaller(int[] nums) {
Integer[] res = new Integer[nums.length];
List<Integer> sorted = new ArrayList<>(nums.length);
// 从后往前计算
for (int i = nums.length - 1; i >= 0; i--) {
int idx = binarySearch(sorted, nums[i]);
res[i] = idx;
sorted.add(idx, nums[i]);
}
return Arrays.asList(res);
}
// 找大于或等于key的第一个位置 low_bound
private static int binarySearch(List<Integer> list, int key) {
int l = 0;
int r = list.size();
for (; l < r;) {
int m = l + (r - l) / 2;
// 不能判断list.get(m) > key
if (list.get(m) < key) {
l = m + 1;
} else {
r = m;
}
}
return l;
}
给定一个整数矩阵,找出最长递增路径的长度。
对于每个单元格,你可以往上,下,左,右四个方向移动。 你不能在对角线方向上移动或移动到边界外(即不允许环绕)。
动态规划:
预处理,先对矩阵的值按从小到大排序(必须),按大小顺序才能保证依赖的子问题都求解过了
dp[i][j]表示以matrix[i][j]结尾的最长递增长度
- 初始
dp[i][j]
都等于1 - 若
matrix[i][j]
四个方向有任意小于它,则可以更新dp[i][j] = max(dp[i][j], 1 + dp[r][c])
class Solution(object):
def longestIncreasingPath(self, matrix):
if not matrix or not matrix[0]:
return 0
m, n = len(matrix), len(matrix[0])
lst = []
for i in range(m):
for j in range(n):
lst.append((matrix[i][j], i, j))
#以值的大小进行排序
lst.sort()
dp = [[0 for _ in range(n)] for _ in range(m)]
for num, i, j in lst:
dp[i][j] = 1
#四个方向尝试
for di, dj in [(0, 1), (1, 0), (0, -1), (-1, 0)]:
r, c = i + di, j + dj
if 0 <= r < m and 0 <= c < n:
#如果小于当前点,则可以更新长度
if matrix[i][j] > matrix[r][c]:
dp[i][j] = max(dp[i][j], 1 + dp[r][c])
return max([dp[i][j] for i in range(m) for j in range(n)])
DFS:
public static int longestIncreasingPath(int[][] matrix) {
if (matrix.length == 0)
return 0;
int m = matrix.length, n = matrix[0].length;
int[][] dirs = { { 0, 1 }, { 1, 0 }, { 0, -1 }, { -1, 0 } };
int[][] map = new int[m][n];
int res = 1;
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
res = Math.max(res, dfs(matrix, i, j, map, dirs));
}
}
return res;
}
// dfs求以点(i,j)结尾的最长递增路径
public static int dfs(int[][] matrix, int i, int j, int[][] map, int[][] dirs) {
if (map[i][j] != 0)
return map[i][j];
int res = 1;
for (int[] dir : dirs) {
int x = i + dir[0], y = j + dir[1];
if (x < 0 || x >= matrix.length || y < 0 || y >= matrix[0].length || matrix[x][y] >= matrix[i][j])
continue;
// 当周围的点小于当前点才递归
res = Math.max(res, 1 + dfs(matrix, x, y, map, dirs));
}
map[i][j] = res;
return res;
}
给定一个未排序的数组,判断这个数组中是否存在长度为 3 的递增子序列。
数学表达式如下:
如果存在这样的 i, j, k, 且满足 0 ≤ i < j < k ≤ n-1,
使得 arr[i] < arr[j] < arr[k] ,返回 true ; 否则返回 false 。
说明: 要求算法的时间复杂度为 O(n),空间复杂度为 O(1) 。
示例 1:
输入: [1,2,3,4,5]
输出: true
a 始终记录最小元素,b 为某个子序列里第二大的数。
接下来不断更新 a,同时保持 b 尽可能的小。
如果下一个元素比 b 大,说明找到了三元组。
class Solution {
public boolean increasingTriplet(int[] nums) {
int s1 = Integer.MAX_VALUE;
int s2 = Integer.MAX_VALUE;
for(int num : nums){
if(num <=s1){
s1 = num;
}else if(num<=s2){
s2 = num;
}else{
return true;
}
}
return false;
}
}
分治,找到任意一个出现次数小于k的字符,对其左右两边分别求解,选两者的最大值
class Solution(object):
def longestSubstring(self, s, k):
if len(s)<k:
return 0
for c in set(s):
#如果当前字符出现次数小于k,则不可能出现在最后结果中
if s.count(c) < k:
return max(self.longestSubstring(t, k) for t in s.split(c))
return len(s)