Leetcode每天五题II-07

  1. 数据流的中位数

有一个数据流,设计一种数据结构,在任意时刻,找到其中的中位数。

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;
	}
  1. 矩阵中的最长递增路径

给定一个整数矩阵,找出最长递增路径的长度。

对于每个单元格,你可以往上,下,左,右四个方向移动。 你不能在对角线方向上移动或移动到边界外(即不允许环绕)。

动态规划:

预处理,先对矩阵的值按从小到大排序(必须),按大小顺序才能保证依赖的子问题都求解过了

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;
	}

  1. 递增的三元组

给定一个未排序的数组,判断这个数组中是否存在长度为 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;
    }
}
  1. 至少有K个重复字符的最长子串

分治,找到任意一个出现次数小于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)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值