48数据流中的中位数
第一次没看到要求排序,还以为题目答案写错了,用排序的内置函数也正好是nlogn
import java.util.ArrayList;
public class Solution {
ArrayList<Integer> list = new ArrayList<>();
public void Insert(Integer num) {
list.add(num);
}
public Double GetMedian() {
ArrayList<Integer> list2 = (ArrayList<Integer>)list.clone();
list2.sort((a,b)->a-b);
int length=list.size();
if(length%2==1){//奇数
return list2.get((length-1)/2).doubleValue();
}
else{
return (list2.get(length/2).doubleValue()+list2.get(length/2-1).doubleValue())/2;
}
}
}
Integer转换为Double:
list2.get((length-1)/2).doubleValue();
法二,用插入排序
因为每次都是增加一个元素,不如直接维护原来的有序数组,这样每次插入的时间复杂度为O(N), GetMedian的时间复杂度为O(1),空间复杂度为O(n)
import java.util.*;
public class Solution {
private ArrayList<Integer> list = new ArrayList<Integer>();
public void Insert(Integer num) {
int i=0;
for( i=0;i<list.size();i++){
if(list.get(i)>num) break;//找到第一个大于它的,插入
}
list.add(i,num);
}
public Double GetMedian() {
int length=list.size();
if(length%2==1){//奇数
return list.get((length-1)/2).doubleValue();
}
else{
return (list.get(length/2).doubleValue()+list.get(length/2-1).doubleValue())/2;
}
}
}
list(index i, E element)可以向指定索引插入元素,后面的自动后移
法3,优先队列
维护两个优先队列,一个最大堆存数组中最小的一半元素,一个最小堆存数组中最大的一半元素,如果是偶数就两个堆顶取平均。
我觉得最难的在于维护这两个堆,保证两个堆的元素刚好分别是最大的一半和最小的一半:
- 元素先进入最大堆(存小数)
- 然后取最大堆的top一一进入最小堆(存大数)
- 如果最大堆的元素个数<最小堆的元素个数,将最小堆的top给最大堆
这样能保证最大堆的元素个数>=最大堆的
import java.util.*;
public class Solution {
private PriorityQueue<Integer> max = new PriorityQueue<Integer>((a,b)->b-a);
private PriorityQueue<Integer> min = new PriorityQueue<Integer>((a,b)->a-b);
public void Insert(Integer num) {
max.offer(num);
min.offer(max.poll());
if(max.size()<min.size()){
max.offer(min.poll());
}
}
public Double GetMedian() {
int maxsize=max.size();
int minsize=min.size();
if(maxsize==minsize){//奇数
return ((double)max.peek()+(double)min.peek())/2;
}
else{
return (double)max.peek();
}
}
}
插入的时间复杂度降为了logn,getMedian为O(1)
49表达式求值
写起来还是很麻烦,主要是判断求值的两种情况:
- 遇到)
- 当前符号的优先级<=符号栈顶的优先级
总体来说分为四种情况:
- 遇到(直接入op栈
- 遇到数字要计算连续数字的值,记得最后i要减1,因为大循环也+1
- )可以计算
- ±*需要判断当前符号和栈顶的优先级,当前符号的优先级<=的时候可以计算
注意计算的时候要while.因为可能存在多个符号需要计算
import java.util.*;
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
* 返回表达式的值
* @param s string字符串 待计算的表达式
* @return int整型
*/
Map<Character,Integer> map=new HashMap<Character,Integer>(){{
put('-',1);
put('+',1);
put('*',2);
}};
public int solve (String s) {
// write code here
Stack<Integer> num = new Stack<>();
Stack<Character> op = new Stack<>();
num.push(0);//防止第一个是负数;
for(int i=0;i<s.length();i++){
//字符
if(!Character.isDigit(s.charAt(i))){
if(s.charAt(i)=='(') op.push('(');
else if(s.charAt(i)==')'){
while(op.peek()!='('){//里面可能需要多次计算
cal(num,op);
}
op.pop();//去掉(
}else{//+-*
while(!op.isEmpty()&& op.peek()!='('){//里面可能需要多次计算
if(map.get(s.charAt(i))<=map.get(op.peek()))
cal(num,op);
else break;
}
op.push(s.charAt(i));
}
}else{//数字
int num1 = 0;
while(i<s.length()&&Character.isDigit(s.charAt(i))){
num1=num1*10+s.charAt(i)-'0';
i++;
}
//因为大循环再加一次
i--;
num.push(num1);
}
}
while (!op.isEmpty() && op.peek() != '(') cal(num, op);//把剩下的算完
return num.pop();
}
public void cal(Stack<Integer> num, Stack<Character> op){
int right = num.pop();
int left = num.pop();
int res=0;
switch(op.pop()){
case '+':
res = left+right;
break;
case '-':
res = left-right;
break;
case '*':
res = left*right;
break;
}
num.push(res);
}
}
时间和空间复杂度都是O(n)
50 两数之和
这题印象很深刻,用哈希表存target出现过的数和对应的索引即可,时间和空间复杂度都是O(n)
import java.util.*;
public class Solution {
/**
*
* @param numbers int整型一维数组
* @param target int整型
* @return int整型一维数组
*/
public int[] twoSum (int[] numbers, int target) {
// write code here
Map<Integer,Integer> m = new HashMap<>();//存值和index
int[] res = new int[2];
for(int i=0;i<numbers.length;i++){
if(m.containsKey(numbers[i])){
res[0] = m.get(numbers[i]);
res[1] = i+1;
break;
}else{
m.put(target-numbers[i],i+1);
}
}
return res;
}
}