目录
一.连续子数组最大和
方法2动态规划
二.查找最小的k对数字
一.从先序遍历还原二叉树
二.完全二叉树
三.判断对称二叉树
四 回文
五.连续子数组最大和
六.TopK问题
思路一如果数据特别大.排序的时间复杂度会很大
思路二:用大根堆或者小根堆然后分别弹出.
思路三:前k堆
七.堆元素排序
八.对象的比较
1.equals:用来比较两个对象相不相同
2.使用compaerable接口
3.Comparator比较器比较
4.总结
5.将优先级队列变成大根堆
一.连续子数组最大和
1.暴力解法
i从第一个元素开始.j从第二个元素开始,然后j开始遍历,计算每个大小.如果第二次比上次大就换成这次的
i再从第二个元素开始,j再从第三个元素开始遍历一直反复计算算到最大值,这里的时间复杂度就是O(n2);
public int FindGreatestSumOfSubArray (int[] array) {
// write code here
int len=array.length;
int max=array[0];
for (int i = 0; i < len; i++) {//只要到最后一个,j也进不去循环,就不会数组越界
int sum=array[i];
if(sum>max){
max=sum;
}
for (int j = i+1; j <len ; j++) {
sum+=array[j];
if(sum>max){
max=sum;
}
}
}
return max;
}
}
这里注意,如果都是负数,很有可能直接输出0所以最好让max初始为数组第一个元素,但是这种算法复杂度过大
方法2动态规划
定义一个max和sum初始值都为第一个元素,然后往后遍历,因为子数组最大要么是前面的加上本身,要么就是本身,
public int getMax(int a,int b){
return a>b?a:b;
}
public int FindGreatestSumOfSubArray (int[] array) {
int sum= array[0];
int max=array[0];
for (int i = 1; i < array.length; i++) {
sum=getMax(sum+array[i],array[i]);
max=sum>max?sum:max;
}
return max;
}
}
二.查找最小的k对数字
首先这道题我们用的是优先队列的方法
因为优先队列底层是一个小根堆,我们需要重写一个比较建立一个内部类
改变比较的方式
然后开始循环,
因为会有k的大小大于遍历的情况
所以需要范围需要在k和数组长度找个最小值,因为
i没必要都走完,就看k的大小就行.因为这是一个升序的数组.
然后建立k个大小的大堆
建立一个顺序表把元素放进里面
再放进优先队列里
放完之后再判断剩下的有没有比他第一个元素大
也就是堆顶元素.因为他是大根堆,堆顶元素一定是最大的
如果比大根堆还大.那就直接换下,找最小的,
但是如果不大.就可以直接跳出循环.因为这是一个升序数组,现在不大以后都会不大
就不用再往后遍历了
因为题目要的是
所以建立一个顺序表
接收优先队列弹出的元素
但是有可能k的值过大,还没弹到第k个,优先表就空了,所以这个时候就需要再建立一个条件,就是他不为空
class Solution {
public List<List<Integer>> kSmallestPairs(int[] nums1, int[] nums2, int k){
PriorityQueue<List<Integer>> priority=new PriorityQueue<>(new Comparator<List<Integer>>() {
@Override
public int compare(List<Integer> o1, List<Integer> o2) {
return o2.get(0)+o2.get(1)-o1.get(0)-o1.get(1);
}//大根堆
});
for (int i = 0; i <Math.min(k,nums1.length); i++) {
// List<Integer> list=new ArrayList<>();
for (int j = 0;j<Math.min(k,nums2.length); j++) {
if(priority.size()<k){
List<Integer> tmpList=new ArrayList<>();
tmpList.add(nums1[i]);
tmpList.add(nums2[j]);
priority.offer(tmpList);
}else{
if(nums1[i]+nums2[j]<priority.peek().get(0)+priority.peek().get(1)){
List<Integer> tmpList=new ArrayList<>();
tmpList.add(nums1[i]);
tmpList.add(nums2[j]);
priority.poll();
priority.offer(tmpList);
}else{
break;
}
}
}
// priority.offer(list);
}
List<List<Integer>> lists=new ArrayList<>();
while(!priority.isEmpty()) {
lists.add(priority.poll());
}
return lists;
}
}
一.从先序遍历还原二叉树
这道题我们考虑模拟递归的方式
之前层序遍历我们用的是队列:因为先进先出
而这里我们一般用的是栈来模拟递归
我们定义一个变量记录每个节点的高度
class Solution {
public TreeNode recoverFromPreorder(String traversal) {
char[] arr=traversal.toCharArray();
Stack<TreeNode> stack=new Stack<>();
int i=0;
while(i<arr.length){
int level=0;
int val=0;
while(i<arr.length&&arr[i]=='-'){
i++;
level++;
}//计算多少- 并跳过
while(i<arr.length&&Character.isDigit(arr[i])){ //防止最后一个跳出循环,数组越界
val=val*10+(arr[i]-'0');//变成数字
i++;
}//到了这里数组下标指向了下一个-了
TreeNode node=new TreeNode(val);//建立新的节点
if(0==stack.size()){
stack.push(node);//第一个的情况
}else{//要么大于要么等于
while(stack.size()!=level){
stack.pop();
}//到了这里就一定相同
TreeNode fatherNode=stack.peek();
if(fatherNode.left==null){
fatherNode.left=node;
}else{
fatherNode.right=node;
}
stack.push(node);//不要忘记放进去
}
}
while(stack.size()>1){
stack.pop();
}
return stack.peek();
}
}
二.完全二叉树
思路:用层序遍历的思路分别放入节点
每放一层就判断是否为null然后弹出
并放入他的左右节点(按顺序)
再循环
每层每层的放弹出,用队列,因为队列可以保证先进先出
先放左节点可以让左节点先判断
原理就是如果不是完全二叉树,如果左右节点顺序放.有null.就会保证在检查出null的时候,后面还有节点
但是如果是完全二叉树是不可能出现这种情况
public boolean isCompleteTree (TreeNode root) {
Queue<TreeNode> queue=new LinkedList<>();
if(root==null) return true;
queue.offer(root);
while(!queue.isEmpty()){
TreeNode top= queue.remove();
if(top==null){
break;
}
queue.offer(top.left);
queue.offer(top.right);
}
while(!queue.isEmpty()){
TreeNode top= queue.remove();
if(top!=null){
return false;
}
}
return true;
}
}
三.判断对称二叉树
首先要结构相同,如果是一个是null一个不是就不可以
而且除了根其他的要全部对称.也就是左节点和右节点相同
所以需要写两个方法
class Solution {
public boolean isSame(TreeNode p,TreeNode q){
if(p==null&&q!=null) return false;
if(p!=null&&q==null) return false;
if(p==null&&q==null) return true;
if(p.val!=q.val) return false;
return isSame(p.left,q.right)&&isSame(p.right,q.left);
}
public boolean isSymmetric(TreeNode root) {
if(root==null) return true;
return isSame(root.left,root.right);
}
}
因为原本的方法参数只有一个,但是判断需要同时判断左边和右边,所以需要再写一个方法
四 回文
这个题目要对字符串方法非常的熟悉
首先不能对字符串本身插入,非常就改变了原来的字符串
所以我们需要新建一个对象来改变
因为插入函数只有sb有
这里注意,StringBuilder没有equlal方法需要转成字符串
这里注意,a假设有2 但是插入会多多插一个位置,所以就会少判断
import java.util.Scanner;
// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
// 注意 hasNext 和 hasNextLine 的区别
while (in.hasNext()) { // 注意 while 处理多个 case
String str = in.nextLine();
String b = in.nextLine();
int count=0;//计数器
for(int i=0;i<=str.length();i++){
StringBuilder sb=new StringBuilder(str);//将str放入存储
sb.insert(i,b);//插入方法只有SB有
StringBuilder ss=new StringBuilder(sb);//防止逆置后 保存原来的字符串
sb.reverse();
if(sb.toString().equals(ss.toString())){//判断是否相同
count++;
}
}
System.out.println(count);
}
}
}
写一个判断回文的方法
public static boolean reverse(StringBuilder sb){
int left=0;
int right=sb.length()-1;
char[] ch=sb.toString().toCharArray();
while(left<right){
if(ch[left]!=ch[right]){
return false;
}
left++;right--;
}
return true;
}
五.连续子数组最大和
六.TopK问题
思路一如果数据特别大.排序的时间复杂度会很大
思路二:用大根堆或者小根堆然后分别弹出.
思路三:前k堆
求前k个最大元素.就把前k个元素建立成一个小根堆.如果有比堆顶大的.就换成他
因为只能根堆顶元素比.剩下两个元素可能比要比的元素小,但是都替换不了.
代码的实现
/**
* 求数组当中前k个最小的元素
* @param //args
*/
public static int[] topK(int[] arr,int k){
PriorityQueue<Integer> maxHeap=new PriorityQueue<>(k, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2-o1;//创建一个大小为k的大根堆
}
});
for (int i = 0; i < arr.length; i++) {
if(maxHeap.size()<k){
maxHeap.offer(arr[i]);//依次放前k个元素
}else{
//从第k+1开始根堆顶元素比较,如果小,就换上去
if(arr[i]<maxHeap.peek()){
//先弹出
maxHeap.poll();
//再放入
maxHeap.offer(arr[i]);
}
}
}
int[] tmp=new int[k];
for (int i = 0; i < k; i++) {
tmp[i]=maxHeap.poll();
}
return tmp;
}
public static void main(String[] args) {
int[] arr={18,21,8,10,34,12};
int[] tmp=topK(arr,3);
System.out.println(Arrays.toString(tmp));
}
为什么是大根堆因为一定要保证每次都跟最大的比较,然后把最大的换掉,所以最后剩下的一定是最小的
tmp是引用变量直接打印打印不出来,要用tostring方法
这道题用优先级队列做,因为优先级队列底层是小根堆,因为要找前k最小的,所以需要大根堆,比较
class Solution {
public List<List<Integer>> kSmallestPairs(int[] nums1, int[] nums2, int k){
PriorityQueue<List<Integer>> priority=new PriorityQueue<>(new Comparator<List<Integer>>() {
@Override
public int compare(List<Integer> o1, List<Integer> o2) {
return o2.get(0)+o2.get(1)-o1.get(0)-o1.get(1);
}//大根堆
});
for (int i = 0; i <Math.min(k,nums1.length); i++) {//防止k比length大,还要继续弹会造成数组越界
// List<Integer> list=new ArrayList<>();
for (int j = 0; j < Math.min(k,nums2.length); j++) {
if(priority.size()<k){
List<Integer> tmpList=new ArrayList<>();
tmpList.add(nums1[i]);
tmpList.add(nums2[j]);
priority.offer(tmpList);
}else{
List<Integer> tmpList=new ArrayList<>();
tmpList.add(nums1[i]);
tmpList.add(nums2[j]);
if(tmpList.get(0)+tmpList.get(1)<priority.peek().get(0)+priority.peek().get(1)){
priority.poll();
priority.offer(tmpList);
}
}
}
// priority.offer(list);
}
List<List<Integer>> lists=new ArrayList<>();
for (int i = 0; i < k&&!priority.isEmpty(); i++) {
lists.add(priority.poll());
}
return lists;
}
}
七.堆元素排序
因为要求数据从0下标到9下标从小到大.应该借助大根堆
找到最大元素再0号下标.然后再放到最后一个元素
再让总元素--(因为最后一个排序好了.不用再排序了)
代码的实现
public void heapSort(){
int end=usedSize-1;//这样就非常巧妙
while(end>0){
int tmp=arr[0];
arr[0]=arr[end];
arr[end]=tmp;//
shiftDown(0,end);//这里传过去的时候end就已经去掉了最后一个
end--;
}
}
八.对象的比较
1.equals:用来比较两个对象相不相同
如果是基本类型可以用equals
但是如果是自定义类,需要重写.
看是否是同一个类,或者另外一个是否是空的
必须成员全部相同
如果没有重写就默认用父类的
引用类型比较 要看地址比较,不是同一个对象地址不一样
2.使用compaerable接口
在类中使用Compareable接口并重写Compaeto方法
这块得自己写,如果我们想要从大王小排序就需要
这里发现.priorityQueue就自动排序了
第一次p添加一张牌
刚开始size=0
因为priorityQueue底层默认是个数组
数组长度默认是11
如果长度不够就要扩容
如果i是0 就放在第一个下标
如果放第二个元素
就要向上调整
可以发现,调用构造方法的时候,comparator是null
那么向上调整的时候就直接jinelse语句
这里就会发现.e会被强转为Comparable类型
所以如果card不实现COMPARABLE接口就会强转不过来会报错
这里就调用Card的compaeto方法所以就算实现接口不重写也不可以
如果第二个就是比第一个大,就不需要交换(因为底层就是个小堆)
但是如果比他小,就需要往下走,交换,进行循环
那如果怎么样实现大堆呢
就改变CARD类本身的comparto方法,让前面的大于后面的大于0
3.Comparator比较器比较
实现一个ccomparator比较器
用户自定义比较器类,实现Comparator接口
但是我们要用PriorityQueue
来进行比较,除了之前的比较方法
还有第一种,第一种如何实现
打开源码可以发现
构造方法默认是null,所以我们得穿一个比较器
先构造一个比较器,然后再构建队列的时候,放进去