2020-10-29刷题

合并K个已排序的链表

TreeNode结构和ListNode结构,自己先在本地写好,以及他们的构造方式,也先写好
1.一开始就应该习惯性的写出输入=null的时候应该返回什么
2.把前k个数进行一个分治,使用二分法,注意即使是分也是需要返回头结点的
3.merge时进行大小的比较,看先把谁接到排好序的节点后面

import java.util.*;
public class Solution {
    public ListNode mergeKLists(ArrayList<ListNode> lists) {
        if(lists.size()==0) return null;
        return devide(lists,0,lists.size()-1);
    }
    private ListNode devide(ArrayList<ListNode> lists,int left,int right){
        if(left>=right) return lists.get(left);
        
        int mid=(left+right)/2;
        ListNode node1=devide(lists,left,mid);
        ListNode node2=devide(lists,mid+1,right);
        ListNode res=merge(node1,node2);
        return res;
    }
    
    private ListNode merge(ListNode node1,ListNode node2){
        if(node1==null) return node2;
        if(node2==null) return node1;
        
        if(node1.val<node2.val){
            node1.next=merge(node1.next,node2);
            return node1;
        }else{
            node2.next=merge(node1,node2.next);
            return node2;
        }
    }
    
}

矩阵的最小路径和

标准二维数组动态规划,注意第一行和第一列的初始化一定要写

import java.util.*;

public class Solution {
    /**
     * 
     * @param matrix int整型二维数组 the matrix
     * @return int整型
     */
    public int minPathSum (int[][] matrix) {
        // write code here
        if(matrix==null || matrix[0]==null) return 0;
        int n=matrix.length;
        int m=matrix[0].length;
        
        int[][] dp=new int[n][m];
        //边界赋初值,除了[0][0]以外,还有第一行和第一列不要写漏了
        dp[0][0]=matrix[0][0];
        for(int i=1;i<n;i++){
            dp[i][0]=dp[i-1][0]+matrix[i][0];
        }
        for(int j=1;j<m;j++){
            dp[0][j]=dp[0][j-1]+matrix[0][j];
        }
        
        for(int i=1;i<n;i++){
            for(int j=1;j<m;j++){
                dp[i][j]=Math.min(dp[(i-1)][j]+matrix[i][j],dp[i][(j-1)]+matrix[i][j]);
            }
        }
        
        
        
        return dp[(n-1)][(m-1)];
    }
}

最长公共子串

要想到这两个子串对象的问题仍然可以转换为一个二维数组的动态规划问题进行解决,并且通过一个index来记录我们需要得到的子串的下标

import java.util.*;
public class Solution {
    public String LCS (String str1, String str2) {
        int m=str1.length(),n=str2.length();
        int[][] dp=new int[m+1][n+1];
        int max=0,index=0;
        for(int i=0;i<m;i++){
            for(int j=0;j<n;j++){
                if(str1.charAt(i)==str2.charAt(j)){
                    dp[i+1][j+1]=dp[i][j]+1;
                    if(max<dp[i+1][j+1]){
                        max=dp[i+1][j+1];
                        index=i+1;//因为是左闭右开的,所以加1
                    }
                }
            }
        }
        return str1.substring(index-max,index);
            
    }
}

二叉树根节点到叶子节点的所有路径表示数之和

为什么写成这个形式的递归sumNumbers(root.left,sum)+sumNumbers(root.right,sum)而不是分开考虑左右子树然后改变sum,这是值得思考的,写过就会发现第一种形式的好处就是当sum被传入左右子树的时候都是一样的值,这样就不会对sum发生改变,所以我们写这种需要传递值的递归的时候第一步是需要重再函数,第二步则是把它拆解成几个小问题的解
要记住递归的本质就是压栈

import java.util.*;

/*
 * public class TreeNode {
 *   int val = 0;
 *   TreeNode left = null;
 *   TreeNode right = null;
 * }
 */

public class Solution {
    /**
     * 
     * @param root TreeNode类 
     * @return int整型
     */
    public int sumNumbers (TreeNode root) {
        if(root==null) return 0;
        return sumNumbers(root,0);

        
    }
    public int sumNumbers(TreeNode root,int sum){
        //递归终止条件
        if(root==null){
            return 0;
        }
        sum=sum*10+root.val;
        if(root.left==null && root.right==null){
            return sum;
        }
        
        return sumNumbers(root.left,sum)+sumNumbers(root.right,sum);
    }
}

买卖股票的最好时机

基本的思想是维持一个单调栈,用的是linkedlist实现的stack,对应的查询栈首和栈尾的操作是peekfirst和peeklast而不是getfirst和getlast,弹出用到的是polllast而不是poll,加入栈尾的操作是addlast,这几个方法需要注意

import java.util.*;


public class Solution {
    /**
     * 
     * @param prices int整型一维数组 
     * @return int整型
     */
    public static int maxProfit (int[] prices) {
        // write code here
        //单调栈
        if(prices.length<=1) return 0;
        int max=0;
        LinkedList<Integer> stack=new LinkedList<>();
        stack.addLast(prices[0]);
        for(int i=1;i<prices.length;i++){
            int last=stack.peekLast();
            while(stack.size()!=0 && last>prices[i]){
                stack.pollLast();
                if(stack.size()!=0){
                    last=stack.peekLast();
                }
            }
            stack.addLast(prices[i]);

            if(prices[i]-stack.peekFirst()>max){
                max=prices[i]-stack.peekFirst();
            }
            //测试
//            StringBuilder sb=new StringBuilder();
//            for(int a:stack){
//                sb.append(a);
//            }
//            System.out.println(sb.toString());

        }
        return max;
    }
}

看了一下别人的代码,同样的时间复杂度,空间复杂度更低,人家这个写得科学多了…只需要用一个buy来记录买入价格,用一个profit来记录利润,然后更新就好了

import java.util.*;


public class Solution {
    /**
     * 
     * @param prices int整型一维数组 
     * @return int整型
     */
    public static int maxProfit (int[] prices) {
        if(prices==null || prices.length==0){
            return 0;
        }
        
        int profit=0,buy=prices[0];
        for(int i=1;i<prices.length;i++){
            buy=Math.min(buy,prices[i]);
            profit=Math.max(profit,prices[i]-buy);
        }
        return profit;
    }
}

设计模式之建造者模式

创建型模式:单例模式/工厂/抽象工厂模式/建造者/原型模式
可以看到这几种模式的写法都是帮我们省去了new的过程,转而用一个类来专门new一个类,也就是创建者

建造者在用户不知道对象的建造过程和细节的时候,用来创建一些复杂对象,[复杂]的时候就用建造者模式,用户只需要给定指定复杂对象的类型和内容就行,比如造车的时候需要用户说出型号,但是不知道汽车是怎么组装的.
这个模式包括director指挥抽象的builder,实现得到具体的builder,由builder生产(new)出具体的产品

  • 使用指挥者
    写一个director类,用于进行制造过程的编写
package shejimoshi;

//指挥:建造者模式的核心,负责指挥建造一个工程,工程如何构建,由他决定
public class Director {

    //建造过程,返回的是一个产品,传入的参数是它所指挥的builder
    //指挥工人按照顺序建房子,核心的建造方法其实在director里面,要改构建过程也是在director里面改,工人是不知道这些的
    public Product build(Builder builder){
        builder.buildA();
        builder.buildB();
        builder.buildC();
        builder.buildD();

        return builder.getproduct();

    }
}

抽象的建造者builder,可以继承出各种各样的工人

package shejimoshi;

//抽象的建造者,不负责建房子,只用于定义方法和接口
public abstract class Builder {
    abstract void buildA();//地基
    abstract void buildB();//钢筋工程
    abstract void buildC();//铺电线
    abstract void buildD();//粉刷


    //得到产品
    abstract Product getproduct();
}

package shejimoshi;

//具体的建造者:工人
public class Worker extends Builder{
    //产品
    private  Product product;

    //让工人生产一个产品,这里就是建造者模式的精髓了
    public Worker(){
        product=new Product();
    }


    @Override
    void buildA() {
        product.setBuildA("地基");
        System.out.println("地基");
    }

    @Override
    void buildB() {
        product.setBuildB("钢筋");
        System.out.println("钢筋");
    }

    @Override
    void buildC() {
        product.setBuildC("电线");
        System.out.println("电线");
    }

    @Override
    void buildD() {
        product.setBuildD("墙面");
        System.out.println("墙面");
    }

    //返回上面得到的产品
    @Override
    Product getproduct() {
        return product;
    }
}

工人建造的产品长这个样子

package shejimoshi;

//产品:房子
public class Product {
    private String buildA;
    private String buildB;
    private String buildC;
    private String buildD;

    public String getBuildA() {
        return buildA;
    }

    public void setBuildA(String buildA) {
        this.buildA = buildA;
    }

    public String getBuildB() {
        return buildB;
    }

    public void setBuildB(String buildB) {
        this.buildB = buildB;
    }

    public String getBuildC() {
        return buildC;
    }

    public void setBuildC(String buildC) {
        this.buildC = buildC;
    }

    public String getBuildD() {
        return buildD;
    }

    public void setBuildD(String buildD) {
        this.buildD = buildD;
    }

    @Override
    public String toString() {
        return "Product{" +
                "buildA='" + buildA + '\'' +
                ", buildB='" + buildB + '\'' +
                ", buildC='" + buildC + '\'' +
                ", buildD='" + buildD + '\'' +
                '}';
    }




}

使用director时

package shejimoshi;

public class DirectorTest {
    public static void main(String[] args) {
        //指挥
        Director director=new Director();

        //指挥 具体的工人完成 产品
        Product built_product=director.build(new Worker());
        System.out.println(built_product.toString());
                /*
        跑出来结果
地基
钢筋
电线
墙面
Product{buildA='地基', buildB='钢筋', buildC='电线', buildD='墙面'}
         */
    }
}
  • 基于工人的
    除了director的方式,也可以不用director,直接在worker里面写具体的建造过程,没看懂这个…
  • 建造者模式的应用场景
    从上面的例子可以看出来,需要生产的产品对象有复杂的内部结构,这些产品对象具备共性,就可以用指挥
    隔离复杂对象的创建和使用,并使用相同的创建过程可以创建不同的产品

建造者与抽象工厂模式相比:
建造者模式返回的是一个组装好的完整产品,而抽象工厂模式返回一系列相关的产品,这些产品位于不同的产品等级结构,构成了一个产品族(比如小米和华为那个例子)
抽象工厂模式中,客户端实例化工厂类,然后调用工厂方法获取所需产品对象,而在建造者模式中客户端可以不直接调用建造者的相关方法,而是通过指挥者来知道如何生成对象,包括对象的组装过程和建造过程,它侧重于一步步构造一个复杂对象,返回一个完整的对象

HashSet

1.8之前:哈希表=数组+链表
1.8之后:哈希表=数组+链表;哈希表=数组+红黑树(提高查询的速度)
哈希表的特点就是查询速度快
数组结构:根据哈希值把元素进行了分组,链表和红黑树结构把哈希值相同的元素连接到一起
如果链表的长度超过了8为,那么就会把链表转换成红黑树,从而提高查询速度

  • Set集合不允许重复元素的原理-这其实对应了面试中常见的一个问题,就是为什么要重写hashcode和equals
import java.util.HashSet;

public class HashSetSaveString {
    public static void main(String[] args) {
        HashSet<String> set=new HashSet<>();
        String s1=new String("abc");
        String s2=new String("abc");
        set.add(s1);
        set.add(s2);

        set.add("重地");
        set.add("通话");
        set.add("abc");
        System.out.println(set);//[重地, 通话, abc]

    }
}

set.add(s1);
add方法会调用s1的hashcode方法,计算abc的哈希值96354
在集合中找有没有96354这个哈希值的元素,发现没有
就会把s1存进去
set.add(s2);
add方法会调用s1的hashcode方法,计算abc的哈希值96354
在集合中找有没有96354这个哈希值的元素,发现有(哈希冲突)
[重点]s2会调用equals方法和哈希值相同的元素进行比较s2.equals(s1),返回true
两个元素的哈希值相同,equals返回true,认定两个元素相同
就不会存s2了
set.add(“重地”);
add方法会调用"重地"的hashcode方法,计算"重地"的哈希值1179395
在集合中找有没有1179395这个哈希值的元素,发现没有
就会把"重地"存进去
set.add(“通话”);
add方法会调用"通话"的hashcode方法,计算"通话"的哈希值1179395
在集合中找有没有1179395这个哈希值的元素,发现有(哈希冲突)
[重点]“通话"会调用equals方法和哈希值相同的元素进行比较"通话”.equals(“重地”),返回false
两个元素的哈希值相同,equals返回false,认定两个元素不同
就会存"通话"

所以用set存储元素使必须重写hashcode方法和equals方法
比如重写person这个对象的hashcode和equals,直接alt+insert就可以了
但是还是要学会自己重写哦

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Person person = (Person) o;
        return age == person.age &&
                Objects.equals(name, person.name) &&
                Objects.equals(a, person.a) &&
                Objects.equals(b, person.b) &&
                Objects.equals(c, person.c) &&
                Objects.equals(d, person.d);
    }

    @Override
    public int hashCode() {

        return Objects.hash(name, age, a, b, c, d);
    }

= =

明天看JVM的底层结构
面试考察点:spring mvc源码,mybatis和redis使用,数据库…这几个学习从11月得开始了,然后自己做项目和项目重构

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
4S店客户管理小程序-毕业设计,基于微信小程序+SSM+MySql开发,源+数据库+论文答辩+毕业论文+视频演示 社会的发展和科学技术的进步,互联网技术越来越受欢迎。手机也逐渐受到广大人民群众的喜爱,也逐渐进入了每个用户的使用。手机具有便利性,速度快,效率高,成本低等优点。 因此,构建符合自己要求的操作系统是非常有意义的。 本文从管理员、用户的功能要求出发,4S店客户管理系统中的功能模块主要是实现管理员服务端;首页、个人中心、用户管理、门店管理、车展管理、汽车品牌管理、新闻头条管理、预约试驾管理、我的收藏管理、系统管理,用户客户端:首页、车展、新闻头条、我的。门店客户端:首页、车展、新闻头条、我的经过认真细致的研究,精心准备和规划,最后测试成功,系统可以正常使用。分析功能调整与4S店客户管理系统实现的实际需求相结合,讨论了微信开发者技术与后台结合java语言和MySQL数据库开发4S店客户管理系统的使用。 关键字:4S店客户管理系统小程序 微信开发者 Java技术 MySQL数据库 软件的功能: 1、开发实现4S店客户管理系统的整个系统程序; 2、管理员服务端;首页、个人中心、用户管理、门店管理、车展管理、汽车品牌管理、新闻头条管理、预约试驾管理、我的收藏管理、系统管理等。 3、用户客户端:首页、车展、新闻头条、我的 4、门店客户端:首页、车展、新闻头条、我的等相应操作; 5、基础数据管理:实现系统基本信息的添加、修改及删除等操作,并且根据需求进行交流信息的查看及回复相应操作。
现代经济快节奏发展以及不断完善升级的信息化技术,让传统数据信息的管理升级为软件存储,归纳,集中处理数据信息的管理方式。本微信小程序医院挂号预约系统就是在这样的大环境下诞生,其可以帮助管理者在短时间内处理完毕庞大的数据信息,使用这种软件工具可以帮助管理人员提高事务处理效率,达到事半功倍的效果。此微信小程序医院挂号预约系统利用当下成熟完善的SSM框架,使用跨平台的可开发大型商业网站的Java语言,以及最受欢迎的RDBMS应用软件之一的MySQL数据库进行程序开发。微信小程序医院挂号预约系统有管理员,用户两个角色。管理员功能有个人中心,用户管理,医生信息管理,医院信息管理,科室信息管理,预约信息管理,预约取消管理,留言板,系统管理。微信小程序用户可以注册登录,查看医院信息,查看医生信息,查看公告资讯,在科室信息里面进行预约,也可以取消预约。微信小程序医院挂号预约系统的开发根据操作人员需要设计的界面简洁美观,在功能模块布局上跟同类型网站保持一致,程序在实现基本要求功能时,也为数据信息面临的安全问题提供了一些实用的解决方案。可以说该程序在帮助管理者高效率地处理工作事务的同时,也实现了数据信息的整体化,规范化与自动化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值