hot100-栈 二分
栈
155. 最小栈
解法一、栈与数组
实际上也可以用辅助栈
class MinStack {
private Deque<int[]> st = new LinkedList<>();
public MinStack() {
st.push(new int[]{0,Integer.MAX_VALUE});
}
public void push(int val) {
st.push(new int[]{val,Math.min(val,st.peek()[1])});
}
public void pop() {
st.pop();
}
public int top() {
return st.peek()[0];
}
public int getMin() {
return st.peek()[1];
}
}
739. 每日温度
解法一、单调栈
class Solution {
public int[] dailyTemperatures(int[] temperatures) {
Deque<Integer> st = new LinkedList<>();
int n = temperatures.length;
int[] res = new int[n];
for(int i = 0;i<n;i++){
while(!st.isEmpty() && temperatures[st.peek()] < temperatures[i]){
res[st.peek()] = i - st.pop();
}//要不然空要不然最后一个大等
st.push(i);
}
return res;
}
}
二分查找
74. 搜索二维矩阵
l指向的是首个元素大于target的一行的前一行。所以要判断首行的首个元素是不是大于target,若是,则l指向-1,再往后走会爆数组下标。
class Solution {
public boolean searchMatrix(int[][] matrix, int target) {
int n = matrix.length,m = matrix[0].length;
int l = -1,r = n;
if(matrix[0][0] > target)return false;
while(l + 1 < r){
int mid = l + (r - l)/2;
if(matrix[mid][0] == target){
return true;
}else if(matrix[mid][0] < target){
l = mid;
}else{
r = mid;
}
}
int t = l;
l = -1;
r = m;
while(l + 1 < r){
int mid = l + (r - l)/2;
if(matrix[t][mid] == target){
return true;
}else if(matrix[t][mid] < target){
l = mid;
}else{
r = mid;
}
}
return l == r;
}
}
解法一、二分
class Solution {
public boolean searchMatrix(int[][] matrix, int target) {
int n = matrix.length,m = matrix[0].length;
int l = -1,r = n;
if(matrix[0][0] > target)return false;
while(l + 1 < r){
int mid = l + (r - l)/2;
if(matrix[mid][0] == target){
return true;
}else if(matrix[mid][0] < target){
l = mid;
}else{
r = mid;
}
}
int t = l;
l = -1;
r = m;
while(l + 1 < r){
int mid = l + (r - l)/2;
if(matrix[t][mid] == target){
return true;
}else if(matrix[t][mid] < target){
l = mid;
}else{
r = mid;
}
}
return l == r;
}
}
34. 在排序数组中查找元素的第一个和最后一个位置
解法一、二分
rR记录第一次的r,在第一次中,l是最后一个小于target的数,r是第一个target(如果target存在)。在第二次中,l是最后一个target(如果target存在),r是target右侧第一个数。
如果第一次的r比第二次的l大,则target不存在。
class Solution {
public int[] searchRange(int[] nums, int target) {
//0 1 2 4 4 6 0
int n = nums.length,l = -1,r = n;
while(l + 1 < r){
int mid = l + (r - l) / 2;
if(nums[mid] < target){
l = mid;
}else{
r = mid;
}
}
// 5 7
int rR = r;
l = -1;
r = n;
while(l + 1 < r){
int mid = l + (r - l) / 2;
if(nums[mid] <= target){
l = mid;
}else{
r = mid;
}
}
return rR > l ? new int[]{-1,-1}: new int[]{rR,l};
}
}
33. 搜索旋转排序数组
解法一、二分
双次二分,第一次找到是分界点(如 3456012) l指向6 r指向0
第二次根据和第一个点的大小关系进行分区段二分
class Solution {
public int search(int[] nums, int target) {
//判断是否大于nums[0],
int n = nums.length,l = -1,r = n;
if(n == 1) return nums[0] == target ? 0 : -1;
while(l + 1 < r){
int mid = l + (r - l)/2;
if(nums[mid] >= nums[0]){
l = mid;
}else{
r = mid;
}
}
//理想情况下 l是左侧最后 r是右侧第一
if(target >= nums[0]){
l = -1;
}else{
r = n;
}
while(l + 1 < r){
int mid = l + (r - l)/2;
if(nums[mid] == target){
return mid;
}else if(nums[mid] < target){
l = mid;
}else {
r = mid;
}
}
return -1;
}
}
153. 寻找旋转排序数组中的最小值
解法一、二分
class Solution {
public int findMin(int[] nums) {
//判断是否大于nums[0],
int n = nums.length,l = -1,r = n;
if(n == 1) return nums[0];
while(l + 1 < r){
int mid = l + (r - l)/2;
if(nums[mid] >= nums[0]){
l = mid;
}else{
r = mid;
}
}
return r != n ? nums[r] : nums[0];
}
}
4. 寻找两个正序数组的中位数
解法一、 二分
大体上分两部分。检索较短的数组,确保效率较高。i是nums1里分割线左侧的点,j是nums2里分割线左侧的点。
数组分割要求:①两侧加起来为(n+m+1)/2 ②a数组最大<b数组最小
因为nums1数组是更小的那个 所以无论如何nums2里一定会被分一部分
class Solution {
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
if(nums1.length > nums2.length){
int[] temp = nums2;
nums2 = nums1;
nums1 = temp;
}
int m = nums1.length,n = nums2.length,l = -1,r = m;
//变小
while(l + 1 < r){
//如果
int i = l + (r - l)/2;
int j = (m + n + 1)/2 - 2 - i;
if(nums1[i] <= nums2[j+1]){//右移
l = i;
}else{
r = i;
}
}
int i = l;
int j = (m+n+1)/2 - 2 - i;
int ai = i < 0 ? Integer.MIN_VALUE : nums1[i];
int bj = j < 0 ? Integer.MIN_VALUE : nums2[j];
int ai1 = i+1 >= m ? Integer.MAX_VALUE : nums1[i+1];
int bj1 = j+1 >= n ? Integer.MAX_VALUE : nums2[j+1];
int maxA = Math.max(ai,bj);
int minB = Math.min(ai1,bj1);
return (m+n)%2==0 ? (double)(maxA+minB)/2 : (double)maxA;
}
}
堆
215. 数组中的第K个最大元素
解法一、堆排序
class Solution {
private void swap(int[] nums,int i,int j){
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
public void heapify(int[] nums, int n,int i) {
int node = i;
int l = i * 2 + 1;
int r = i * 2 + 2;
if(l < n && nums[l] > nums[node]){
node = l;
}
if(r < n && nums[r] > nums[node]){
node = r;
}
if(node != i){
swap(nums,i,node);
heapify(nums,n,node);
}
}
public int findKthLargest(int[] nums, int k) {
int n = nums.length;
for(int i = n/2-1;i >= 0;i--){
heapify(nums,n,i);
}
for(int i = n-1;i >= n-k;--i){
swap(nums,0,i);
heapify(nums,i,0);
}
return nums[n-k];
}
}
347. 前 K 个高频元素
解法一、堆排序
class Solution {
private Map<Integer,Integer> hm = new HashMap<>();
public int[] topKFrequent(int[] nums, int k) {
int n = nums.length;
for(int i = 0;i < n;i++){
hm.put(nums[i],hm.getOrDefault(nums[i],0)+1);
}
PriorityQueue<int[]> queue = new PriorityQueue<int[]>(new Comparator<int[]>() {
@Override
public int compare(int[] o1, int[] o2) {
return o1[1] - o2[1];
}
});
for(Map.Entry<Integer,Integer> h : hm.entrySet()){
int num = h.getKey(),count = h.getValue();
if(queue.size() == k){
if(queue.peek()[1] < count){
queue.poll();
queue.offer(new int[]{num,count});
}
}else{
queue.offer(new int[]{num,count});
}
}
int[] res = new int[k];
for(int i = k-1;i >=0;i--){
res[i] = queue.poll()[0];
}
return res;
}
}
解法二、自建
class Solution {
Map<Integer,Integer> map;
public int[] topKFrequent(int[] nums, int k) {
int[] ans = new int[k];
map = new HashMap<>();
for (int num : nums) {
map.put(num,map.getOrDefault(num,0)+1);
}
int[] arr= new int[map.size()];
int i=0;
for (Integer num : map.keySet()) {
arr[i++] = num;
}
//建立小根堆
buildMinHead(arr,k);
for (int j = k; j < arr.length; j++) {
if(map.get(arr[j]) > map.get(arr[0])){
swap(arr,j,0);
minHeap(arr,0,k);
}
}
ans = Arrays.copyOf(arr,k);
return ans;
}
private void buildMinHead(int[] arr, int k) {
for (int i = k/2; i >=0 ; i--) {
minHeap(arr,i,k);
}
}
private void minHeap(int[] arr, int i, int heapSize) {
int l = i * 2+1;
int r = i * 2+2;
int min = i;
if(l < heapSize && map.get(arr[l]) < map.get(arr[min])) min = l;
if(r < heapSize && map.get(arr[r]) < map.get(arr[min])) min = r;
if(min != i){
swap(arr,i,min);
minHeap(arr,min,heapSize);
}
}
public void swap(int[] arr,int i,int j){
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
// public int[] topKFrequent(int[] nums, int k) {
// int[] ans = new int[k];
// Map<Integer,Integer> map = new HashMap<>();
// for (int num : nums) {
// map.put(num,map.getOrDefault(num,0)+1);
// }
// PriorityQueue<int[]> pq = new PriorityQueue<>((o1, o2) -> o2[1]-o1[1]);
// for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
// pq.add(new int[]{entry.getKey(),entry.getValue()});
// }
// for (int i = 0; i < k; i++) {
// ans[i] = pq.poll()[0];
// }
// return ans;
// }
}
295. 数据流的中位数
解法一、堆
较慢写法
class MedianFinder {
private PriorityQueue<Integer> left = new PriorityQueue<>((a,b) -> b - a);//大根堆
private PriorityQueue<Integer> right = new PriorityQueue<>();//小根堆
public MedianFinder() {
}
public void addNum(int num) {
if(left.size() == right.size()){
right.offer(num);
left.offer(right.poll());
}else{
left.offer(num);
right.offer(left.poll());
}
}
public double findMedian() {
if(left.size() > right.size()){
return left.peek();
}
return (left.peek() + right.peek())/2.0;
}
}
较快写法
class MedianFinder {
private PriorityQueue<Integer> minQue;
private PriorityQueue<Integer> maxQue;
public MedianFinder() {
minQue = new PriorityQueue<>((o1,o2)->o1-o2);
maxQue = new PriorityQueue<>((o1,o2)->o2-o1);
}
public void addNum(int num) {
if(minQue.isEmpty()||num>=minQue.peek()){
minQue.offer(num);
}else{
maxQue.offer(num);
}
if(minQue.size()>maxQue.size()+1){
maxQue.offer(minQue.poll());
}else if(maxQue.size()>minQue.size()){
minQue.offer(maxQue.poll());
}
}
public double findMedian() {
if(minQue.size()==maxQue.size()){
return (minQue.peek()+maxQue.peek())/2.0;
}else{
return minQue.peek();
}
}
}
①对于Map 通过该种方式进行遍历
for(Map.Entry<Integer,Integer> h : hm.entrySet()) {
int num = h.getKey(), count = h.getValue();
}
② 使用PriorityQueue表示堆排调库