每日一题 Day18
A、count(*)一定可以返回数值,如果t1中没有数据,返回0
B、max返回null可能有两种情况 1)t1中没有数据 2)col1字段全部都是null
C、concat是字符串拼接函数,如果拼接的其中一个字符串为null,结果就是null
A、默认创建的外键是严格模式(必须在主表中,关联的键有该数据)
其他模式外键可以为空
B、候选键:可以标识数据的唯一性的最小集
top,是sql srever中的关键字,用于求前n条数据(如果要查从m条到n条,要写子查询)
语法:select top n 查询字段 from……
A、phoneno是数字组成(使用数值数据类型),和字符串可以比较,但是会进行类型转换(有点耗时)
B、模糊匹配,可以使用索引
C、使用函数,不会再使用索引,全部扫i描(全部数据遍历),函数本身的执行也需要耗时
RDBMS是关系型数据库
D、hadoop是大数据方向的数据库,不是关系型
import java.util.*; public class Main{ public static void main(String[]args){ Scanner sc=new Scanner(System.in); while(sc.hasNext()){//多组输入 int m=sc.nextInt(); System.out.println(num(m)); } } public static int num(int m){ if(m<=2){ return 1; } return num(m-1)+num(m-2); } }
题目:HJ71 字符串通配符
import java.util.*; public class Main{ public static void main(String[]args){ Scanner sc=new Scanner(System.in); while(sc.hasNextLine()){ String t=sc.nextLine();//通配符字符串 String s=sc.nextLine();//字符串 System.out.println(match(t,s)); } } public static boolean match(String t,String s){ //因为要一个字符一个字符匹配,所以先拆成一个个字符放到数组中 char[] ct=t.toCharArray(); char[] cs=s.toCharArray(); int lt=ct.length; int ls=cs .length; boolean[][] dp=new boolean[ls+1][lt+1];//长:ls 宽:lt dp[0][0]=true;//base case for(int i=0;i<=ls;i++){//i用来遍历字符串数组 for(int j=1;j<=lt;j++){//j用来遍历通配符数组 if(ct[j-1]=='*'){//当通配符时*时(要单独判断,因为*可以匹配多个字符) if(i==0){此时没有字符串与*匹配 dp[i][j]=dp[i ][j-1];//此时前一个是啥就是啥 }else{ if(cs[i-1]=='.'||cs[i-1]>='A'&&cs[i-1]<='Z' ||cs[i-1]>='a'&&cs[i-1]<='z' ||cs[i-1]>='0'&&cs[i-1]<='9'){ //如果截止到*的通配符和当前要匹配字符的前一个字符匹配成功,则为true(此时*匹配多个字符) //如果*之前的通配符和要匹配字符匹配成功,则也为true(此时*匹配一个字符) dp[i][j]=dp[i-1][j]||dp[i][j-1]; } } }else{//当通配符不是*时 if(i>0&&defs(ct[j-1],cs[i-1])){//defs方法,用来看通配符表达式和字符串是不是相等 //如果当前字符匹配成功,要看一下前面的字符是否匹配成功,都成功才成功 dp[i][j]=dp[i-1][j-1]; } } } } return dp[ls][lt]; } public static boolean defs(char t,char s){//判断字符是否匹配 if(t=='?') return true; if(t>='a'&&t<='z'){ t=(char)(t-'a'+'A');//把小写字母转换成大写字母 } if(s>='a'&&s<='z'){ s=(char)(s-'a'+'A'); } return s==t; } }
每日一题 Day19
A、链表的存储数据可以不一致,但逻辑顺序必须一致
B、链表的存储空间也是不连续的
顺序存储结构:顺序表
二叉树中只有完全二叉数可以使用顺序表存储
A、非完全二叉树只能采用链式存储
B、堆是一个完全二叉树,可以使用数组存储
C、D、队列和栈都属于顺序表
递归函数的终止条件:函数调用过程中有一个分支直接return不会一直调用下去
都列出来,看是小堆还是大堆,都不符合就不是堆
此时内存中放不下所有要排序的数据,需要进行外部排序,借助外部的空间(磁盘)进行排序。通常外部排序利用:多路归并排序
先将1GB分为大小相等的20份,每份大小为50MB,依次将每份数据读入内存中进行排序(内部排序:快排等),然后在外部空间进行这20份的归并过程
树的深度:最大的节点高度,从根节点开始算第一层
import java.util.*; public class Main{ public static void main(String[]args){ Scanner sc=new Scanner(System.in); while(sc.hasNext()){ String str1=sc.nextLine(); String str2=sc.nextLine(); if(str1.length()<str2.length()){ System.out.println(getMaxSubstr(str1,str2)); }else{ System.out.println(getMaxSubstr(str2,str1)); } } } //假设str1长度短 public static String getMaxSubstr(String str1,String str2){ char[]arr1=str1.toCharArray(); char[]arr2=str2.toCharArray(); int len1=arr1.length; int len2=arr2.length; //最长子串的起始位置 int start=0; //最长的子串长度 int maxLen=0; //多增加一行一列,作为辅助状态 int[][] maxSubLen=new int[len1+1][len2+1]; //以str1的第i个字符结尾和以str2的第j个字符结尾的最长公共字串的长度 for(int i=1;i<=len1;i++){ for(int j=1;j<=len2;j++){ //如果第i个字符和第j个字符相等,则进行累加 if(arr1[i-1]==arr2[j-1]){ maxSubLen[i][j]=maxSubLen[i-1][j-1]+1; //更新 if(maxLen<maxSubLen[i][j]){ maxLen=maxSubLen[i][j]; start=i-maxLen; } } } } return str1.substring(start,start+maxLen); } }
题目:36846-汽水瓶
import java.util.*; public class Main{ public static void main(String[]args){ Scanner sc=new Scanner(System.in); while(sc.hasNext()){ int num=sc.nextInt(); if(getNum(num)!=0){ System.out.println(getNum(num)); } } } public static int getNum(int num){//num为空瓶的个数 //汽水的个数 int sum=0; while(num>1){ //兑换的汽水的个数num/3 sum+=num/3; //剩余的空瓶子 num=num/3+num%3; if(num==2){ //借一瓶 sum++; break; } } return sum; } }
每日一题 Day20
栈和队列插入的时间复杂度都是O( 1 )
叶子节点的个数=度为2的节点个数+1
当前序遍历和中序遍历序列相同时,一定是一个单方向树(链表)
建堆:是从最后一个非叶子节点开始进行元素的shiftDown操作
近乎有序的数组中,冒泡排序是比较优秀的,当发现元素没有交换时,认为此时数组已经有序,排序退出
归并和堆排是比较稳定的:为O(nlogn)
题目:36899-公共字串计算
import java.util.*; public class Main{ public static void main(String[]args){ Scanner sc=new Scanner(System.in); String str1=sc.nextLine(); String str2=sc.nextLine(); System.out.println(getMaxLen(str1,str2)); } public static int getMaxLen(String str1,String str2){ char[]arr1=str1.toCharArray(); char[]arr2=str2.toCharArray(); int len1=arr1.length; int len2=arr2.length; int maxLen=0; int[][]maxSubLen=new int[len1+1][len2+1]; for(int i=1;i<=len1;i++){ for(int j=1;j<=len2;j++){ if(arr1[i-1]==arr2[j-1]){ //状态转移方程 maxSubLen[i][j]=maxSubLen[i-1][j-1]+1; } //更新最大值 if(maxLen<maxSubLen[i][j]){ maxLen=maxSubLen[i][j]; } } } return maxLen; } }
题目:36836-字符串反转
import java.util.*; public class Main{ public static void main(String[]args){ Scanner sc=new Scanner(System.in); String str=sc.nextLine(); char[]arr=str.toCharArray(); int len=arr.length; int i=0; int j=len-1; while(i<j){ char tmp=arr[i]; arr[i]=arr[j]; arr[j]=tmp; i++; j--; } String s=new String(arr); System.out.println(s); } }
每日一题 Day21
B、循环队列用的是数组
哈夫曼树是带权值的树(与元素大小顺序无关)
增大装载因子会增加元素冲突,使查找变慢
堆排序的方式:先将0位置元素和最后位置元素交换,然后继续在剩下的元素中调整为最大堆
最坏情况下:
希尔排序:比O(NlogN)大
快排:当出现大量重复元素或者数组几乎有序时,递归树退化为链表,为O(N^2)
堆排:是一个稳定的排序O(NlogN)
冒泡:O(N^2)
题目:MP3光标位置
import java.util.*; public class Main{ public static void main(String[]args){ Scanner sc=new Scanner(System.in); String numStr=sc.nextLine(); String orderStr=sc.nextLine(); mouseMove(numStr,orderStr); } public static void mouseMove(String numStr,String orderStr){ //歌曲数量 int n=Integer.parseInt(numStr); //指令数组:UD char[] order=orderStr.toCharArray(); //当前鼠标所在的位置 int mouse=1;//光标初始的位置为第1首歌 //显示列表所在的起始位置 int first=1; //指令处理 //歌曲数量n<=4时 if(n<=4){ for(int i=0;i<order.length;i++){ //光标在第一首歌曲上时,按Up键光标挪到最后一首歌曲 if(mouse==1&&order[i]=='U'){ mouse=n; } //光标在最后一首歌曲时,按Down键光标挪到第一首歌曲 else if(mouse==n&&order[i]=='D'){ mouse=1; } //其他情况下用户按Up键,光标挪到上一首歌曲 else if(order[i]=='U'){ mouse--; } //用户按Down键,光标挪到下一首歌曲 else if(order[i]=='D'){ mouse++; } } //输出 //打印当前的显示列表 for(int i=1;i<n;i++){ System.out.print(i+" "); } System.out.println(n); //打印当前歌曲 System.out.println(mouse); } //歌曲数量n>4时 else{ for(int i=0;i<order.length;i++){ //屏幕显示的是第一页(即显示第1 – 4首)时, //光标在第一首歌曲上,用户按Up键后,屏幕要显示最后一页(即显示第7-10首歌), //同时光标放到最后一首歌上。 if(first==1&&mouse==1&&order[i]=='U'){ //最后一页的起始位置为歌曲数-3 first=n-3; mouse=n; } //屏幕显示最后一页时,光标在最后一首歌曲上, //用户按Down键,屏幕要显示第一页,光标挪到第一首歌上。 else if(first==n-3&&mouse==n&&order[i]=='D'){ first=1; mouse=1; } //屏幕显示的不是第一页时,光标在当前屏幕显示的第一首歌曲时, //用户按Up键后,屏幕从当前歌曲的上一首开始显示,光标也挪到上一首歌曲 else if(first!=1&&mouse==first&&order[i]=='U'){ first--; mouse--; } //光标当前屏幕的最后一首歌时的Down键处理也类似 else if(first!=n-3&&mouse==first+3&&order[i]=='D'){ first++; mouse++; } //其他情况,不用翻页,只是挪动光标就行。 else if(order[i]=='U'){ mouse--; } else if(order[i]=='D'){ mouse++; } } //输出 //打印当前的显示列表 for(int i=first;i<first+3;i++){ System.out.print(i+" "); } System.out.println(first+3); //打印当前歌曲 System.out.println(mouse); } } }
题目:洗牌
import java.util.*; public class Main{ public static void main(String[]args){ Scanner sc=new Scanner(System.in); int groups=sc.nextInt(); for(int i=0;i<groups;i++){ //读入每组数据 int n=sc.nextInt(); int k=sc.nextInt(); int[] cards=new int[2*n]; for(int j=0;j<2*n;j++){ cards[j]=sc.nextInt(); } //洗牌 playCard(cards,n,k); } } //n为牌数一半,k为洗牌次数 public static void playCard(int[] cards,int n,int k){ //编号为i是牌,最后放到2*i位置 //编号为i+n的牌最后放到2*i+1位置 for(int i=0;i<k;i++){ //一次洗牌的过程 int [] newCards=new int [cards.length]; for(int j=0;j<n;j++){ //遍历编号为0~n-1的牌 newCards[2*j]=cards[j]; newCards[2*j+1]=cards[j+n]; } cards=newCards; } //洗完之后从上往下打印 printCard(cards); } public static void printCard(int[]cards){ for(int i=0;i<cards.length-1;i++){ System.out.print(cards[i]+" "); } System.out.println(cards[cards.length-1]); } }
每日一题 Day22
用到队列的遍历只有层序遍历
两个有序的子区间个数都为n,最好的情况为第二个区间都比第一个区间大,只需要比较n次即可
快排:每当交换一次元素,就会产生一个新的逆序对
简单插入排序和简单选择排序会减少逆序对
冒泡排序是交换相邻的元素,不一定会产生逆序对
import java.util.*; public class Main{ public static void main(String[]args){ Scanner sc=new Scanner(System.in); while(sc.hasNext()){ String str=sc.nextLine(); find(str); } } public static void find(String str){ char[] arr=str.toCharArray(); int[] check=new int[128]; boolean flg=false; for(int i=0;i<arr.length;i++){ check[arr[i]]++; } for(int i=0;i<arr.length;i++){ if(check[arr[i]]==1){ System.out.println(arr[i]); flg=true; break; } } if(flg==false){ System.out.println(-1); } } }
题目:小易的升级之路
import java.util.*; public class Main{ public static void main(String[] args){ Scanner sc=new Scanner(System.in); while(sc.hasNext()){ int n=sc.nextInt();//怪物的数量 int x=sc.nextInt();//小易的初始能力值 int[] nums=new int[n];//怪物的防御力 for(int i=0;i<n;i++){ nums[i]=sc.nextInt(); if(nums[i]<=x){ x+=nums[i]; } else{ x+=gcd(x,nums[i]); } } System.out.println(x); } } public static int gcd(int a,int b){//求最大公约数 int c; while((c=a%b)!=0){ a=b; b=c; } return b; } }
每日一题 Day23
递归次数与初始数据的排列次序有关
平均查找长度=查找次数/数组的元素个数
题目:计算字符串的编辑距离
import java.util.*; public class Main{ public static void main(String[]args){ Scanner sc=new Scanner(System.in); while(sc.hasNext()){ String str1=sc.nextLine(); String str2=sc.nextLine(); System.out.println(getDistance(str1,str2)); } } public static int getDistance(String str1,String str2){ char[] wd1=str1.toCharArray(); char[] wd2=str2.toCharArray(); int len1=wd1.length; int len2=wd2.length; //编辑距离矩阵 int[][] dist=new int[len1+1][len2+1]; //初始状态: //从i个字符变成0个字符,需要删除i个字符:F[i,0]=i //从0个字符变成j个字符,需要插入j个字符:F[0,j]=j for(int i=0;i<=len1;i++){ dist[i][0]=i; } for(int j=0;j<=len2;j++){ dist[0][j]=j; } //状态转移 for(int i=1;i<=len1;i++){ for(int j=1;j<=len2;j++){ //首先求出插入和删除的最小值 dist[i][j]=Math.min(dist[i-1][j],dist[i][j-1])+1; //再和替换作比较 if(wd1[i-1]==wd2[j-1]){//此时不需要替换 dist[i][j]=Math.min(dist[i][j],dist[i-1][j-1]); }else{//此时需要替换 dist[i][j]=Math.min(dist[i][j],dist[i-1][j-1]+1); } } } return dist[len1][len2]; } }
题目:微信红包
import java.util.*; public class Gift { public int getValue(int[] gifts, int n) { Arrays.sort(gifts); int mid=gifts[n/2]; int count=0; //统计中间位置数据出现的次数 for(int g:gifts){ if(g==mid){ count++; } } if(count>n/2){ return mid; }else{ return 0; } } }
public class Gift { public int getValue(int[] gifts, int n) { // write code here Map<Integer,Integer>map=new HashMap<>(); for(int g:gifts){ if(map.containsKey(g)){ map.put(g,map.get(g)+1); }else{ map.put(g,1); } if(map.get(g)>=n/2){ return g; } } return 0; } }
每日一题 Day24
每进行一次快排,标定点一定处在最终位置
进行两次快排,则至少有两个元素到达最终位置
题目:迷宫问题
import java.util.*; import java.io.*; class Node{ int x; int y; public Node(int x,int y){ this.x=x; this.y=y; } } public class Main{ public static void main(String[] args) { Scanner sc=new Scanner(System.in); while(sc.hasNext()) { int row = sc.nextInt(); int col = sc.nextInt(); //创建迷宫矩阵 int[][] mat = new int[row][col]; //读入迷宫数据 for(int i = 0; i < row; i++) { for(int j = 0; j < col; j++) { mat[i][j] = sc.nextInt(); } } //搜索最短路径 ArrayList<Node> path = new ArrayList<>(); ArrayList<Node> minPath = new ArrayList<>(); int[][] book = new int[row][col]; getMinPath(mat, row, col, 0, 0, book, path, minPath); //打印最短路径 for(Node n : minPath) { System.out.println("(" + n.x + "," + n.y + ")"); } } } //mat表示迷宫矩阵;x,y为当前位置 //book为标记矩阵,标记当前位置是否走过 //path保存路径中的每个位置 //minpath保存最小路径 public static void getMinPath(int[][] mat,int row,int col, int x,int y,int[][]book,ArrayList<Node>path,ArrayList<Node>minPath){ //判断(x,y)是否越界,是否走过,是否有障碍 if(x<0||x>=row||y<0||y>=col ||book[x][y]==1||mat[x][y]==1){ return; } //把当前位置存入路径中 path.add(new Node(x,y)); //标记当前位置 book[x][y]=1; //判断当前位置是否为目的位置 if(x==row-1&&y==col-1){ //如果当前位置为目的位置,证明找到了一条路径 //此时判断当前路径是否为最短路径 if(minPath.isEmpty()||path.size()<minPath.size()){ //更新更短路径 minPath.clear(); for(Node n:path){ minPath.add(n); } } } //继续搜索(x,y)的上下左右四个方向 getMinPath(mat,row,col,x+1,y,book,path,minPath); getMinPath(mat,row,col,x-1,y,book,path,minPath); getMinPath(mat,row,col,x,y-1,book,path,minPath); getMinPath(mat,row,col,x,y+1,book,path,minPath); //把当前位置从路径中删掉,寻找新的路径 path.remove(path.size()-1); book[x][y]=0; } }
题目:年终奖
import java.util.*; public class Bonus { public int getMost(int[][] board) { int row=board.length; int col=board[0].length; //处理第一行:只能从左向右走 for(int i=1;i<col;i++){ board[0][i]+=board[0][i-1]; } //处理第一列:只能从上向下走 for(int i=1;i<row;i++){ board[i][0]+=board[i-1][0]; } //剩余位置 for(int i=1;i<row;i++){ for(int j=1;j<col;j++){ board[i][j]+=Math.max(board[i-1][j],board[i][j-1]); } } return board[row-1][col-1]; } }