java 判断二维数组中是否存在某个数
题目:给定一个二维数组,判断其中是否存在某个数
例如:给定数组{{1,2,8,9},{2,4,9,12},{4,7,10,13},{6,8,11,15}},判断7是否存在于数组中
public boolean find(int[][] matrix,int rows,int columns,int number){ if(matrix!=null&&rows>0&&columns>0){ int row = 0; int column = columns-1; while(row=0){ if(matrix[row][column]==number){ return true; } if(matrix[row][column]>number){ column--; }else{ row++; } } } return false; }
青蛙跳台阶的算法
一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果)。
如果n=1,只有一种跳法,那就是1
如果n=2,那么有两种跳法,2,[1,1]
如果n=3,那么有三种跳法,[1,1,1],,[1,2],[2,1]
如果n=4,那么有五种跳法,[1,1,1,1],[1,1,2],[1,2,1],[2,1,1],[2,2]
如果n=5,那么有八种跳法,[1,1,1,1,1],[1,1,1,2],[1,1,2,1],[1,2,1,1],[2,1,1,1],[2,2,1],[2,1,2],[1,2,2]
结果为1,2,3,5,8 这不特么是斐波那切数列嘛
递归做法: public static int jump(int n){ if (n==0) return 0; if (n==1) return 1; if (n==2) return 2; return jump(n-1)+jump(n-2); } 非递归做法: public static int jump2(int n){ if (n==0) return 0; if (n==1) return 1; if (n==2) return 2; int n1=1; int n2=2; int count=2; while (count++<=n){ int tmp=n1; n1=n2; n2=tmp+n2; } return n2; }
2、3. 一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。
f(n) = f(n-1) + f(n-2) + f(n-3) + ... + f(n-(n-1)) + f(n-n)= f(0) + f(1) + f(2) + f(3) + ... + f(n-2)+f(n-1)
f(n-1) = f(0) + f(1)+f(2)+f(3) + ... + f((n-1)-1) = f(0) + f(1) + f(2) + f(3) + ... + f(n-2)
so f(n)=2*f(n-1)
public int Jump3(int n) {
if (n <= 1) {
return 1;
} else {
return 2 * Jump3(n - 1);
}
}
4. 一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个m级的台阶总共有多少种跳法。
先列多项式:
f(n) = f(n-1) + f(n-2) + f(n-3) + ... + f(n-m)
f(n-1) = f(n-2) + f(n-3) + ... + f(n-m) + f(n-m-1)
化简得:f(n) = 2f(n-1) - f(n-m-1)
public static int Jump4(int n,int m ) { //当大于m的时候是上面的公式 if(n > m){ return 2*Jump4(n-1, m)-Jump4(n-1-m, m); } //当小于等于m的时候就是和n级的相同了 if (n <= 1) { return 1; } else { return 2 * Jump4(n - 1,n); } } }
贪心算法和动态规划算法
public void quickSort(int[] num, int st, int ed) { if (st >= ed) return; int left = st; int right = ed; int value = num[left]; while (left < right) { while(left < right && num[right] >= value){ right--; } num[left] = num[right]; while(left < right && num[left] < value){ left++; } num[right] = num[left]; } int mid = left; num[mid] = value; quickSort(num, st, mid - 1); quickSort(num, mid + 1, ed); } public static void main(String[] args) { QuickSort quickSort = new QuickSort(); int[] num = {3, 7, 4, 2, 5, 8, 1}; quickSort.quickSort(num, 0, 6); for (int t : num) { System.out.println(t); } }
import java.util.Arrays; public class MergeSort { public int[] mergeSort(int[] num) { if (num.length <= 1) return num; int mid = num.length / 2; int[] left = Arrays.copyOfRange(num, 0, mid); int[] right = Arrays.copyOfRange(num, mid, num.length); return mergeArrays(mergeSort(left), mergeSort(right)); } private int[] mergeArrays(int[] mergeSort1, int[] mergeSort2) { int[] result = new int[mergeSort1.length + mergeSort2.length]; int i = 0, j = 0, k = 0; while (i < mergeSort1.length && j < mergeSort2.length) { if (mergeSort1[i] < mergeSort2[j]) { result[k++] = mergeSort1[i++]; } else { result[k++] = mergeSort2[j++]; } } while (i < mergeSort1.length) { result[k++] = mergeSort1[i++]; } while (j < mergeSort2.length) { result[k++] = mergeSort2[j++]; } return result; } public static void main(String[] args) { MergeSort mergeSort = new MergeSort(); int[] num = {3, 7, 4, 2, 5, 8, 1}; num = mergeSort.mergeSort(num); for (int t : num) { System.out.println(t); } } }
public class Solution { public int findK(int[] num, int k) { return quickSort(num, 0, num.length - 1, k - 1); } public int quickSort(int[] num, int st, int ed, int k) { if (st >= ed) return num[st]; int value = num[st]; int left = st; int right = ed; while (left < right) { while (left < right && num[right] >= value) { right--; } num[left] = num[right]; while (left < right && num[left] < value) { left++; } num[right] = num[left]; } num[left] = value; if (left == k) return value; else if (left < k) { return quickSort(num, left + 1, ed, k); } else { return quickSort(num, st, left, k); } } public static void main(String[] args) { Solution solution = new Solution(); int[] num = {1,8,8,7,4,1,5,1,5,7}; System.out.println(solution.findK(num, 1)); System.out.println(solution.findK(num, 2)); } }
1.B+树和B树的区别
B+树的数据都在叶子结点上,而B树的非根非叶节点也是数据节点,所以B+树的查询更稳定。
B+树有两个指针,一个指向root节点,一个指向叶子节点的最左侧,因此其范围查询效率更高,而B树则需要中序遍历B树。
同阶的情况下,B+树节点中的关键字要比B树多一个,并且B+树的中间节点不保存数据,所以磁盘也能够容纳更多结点元素,因此B+树更加矮胖,查询效率也更高。
2.红黑树
红黑树是一个自平衡二叉查找树。时间复杂度O(log n)
- 节点颜色为红或者黑
- 根结点是黑色
- 叶节点(NIL结点,空结点)为黑
- 红节点的孩子为黑(路径上不能有两个连续的红节点)
- 从根到叶子节点路径中的黑节点数相等
3.红黑树和平衡二叉树的区别
平衡二叉树和高度相关,保持平衡的代价更高(多次旋转),因此适用于插入、删除较少,查询较多的场景。
红黑树和高度无关,旋转次数较少,因此适用于插入、删除较多的场景。
动态规划算法
与贪心法的区别:不是由上一步的最优解直接推导下一步的最优解,所以需要记录上一步的所有解 (下例中的F[i][j]就表示第i行的j个解)
能使用动态规划算法的条件:
如果一个问题被划分各个阶段之后,阶段I中的状态只能由阶段I-1中的状态通过状态转移方程得来,与其它状态没有关系,特别是与未发生的状态没有关系,那么这个问题就是“无后效性”的,可以用动态规划算法求解
1。定义阶段:第i行第j列的值a[i][j]
2。定义状态:走到第i行第j列的最大值F[i][j]
3。状态转移方程:F[i][j] = a[i][j]+max(F[i+1][j], F[i+1][j+1])
4。定义边界条件:当i = n时,F[i][j] = a[i][j]; 即一开始可以直接得出的局部最优解
框架
1.Mybatis动态代理
- 构建SqlSessionFactory过程
构建主要分为2步:
- 通过XMLConfigBuilder解析配置的XML文件,读出配置参数,包括基础配置XML文件和映射器XML文件;
- 使用Configuration对象创建SqlSessionFactory,SqlSessionFactory是一个接口,提供了一个默认的实现类DefaultSqlSessionFactory。
说白了,就是将我们的所有配置解析为Configuration对象,在整个生命周期内,可以通过该对象获取需要的配置。
- 映射器的动态代理
Mapper映射是通过动态代理来实现的,使用JDK动态代理返回一个代理对象,供调用者访问。
首先看看实现InvocationHandler接口的类,它是执行本代理方法的关键,可以看到,Mapper是一个接口,会生成MapperMethod对象,调用execute方法。
- SqlSession的4大对象
通过上面的分析,映射器就是一个动态代理对象,进入到了MapperMethod的execute方法,它经过简单的判断就进入了SqlSession的删除、更新、插入、选择等方法,这些方法如何执行是下面要介绍的内容。
Mapper执行的过程是通过Executor、StatementHandler、ParameterHandler和ResultHandler来完成数据库操作和结果返回的,理解他们是编写插件的关键:
- Executor:执行器,由它统一调度其他三个对象来执行对应的SQL;
- StatementHandler:使用数据库的Statement执行操作;
- ParameterHandler:用于SQL对参数的处理;
- ResultHandler:进行最后数据集的封装返回处理;
- sql执行的过程
- 在MyBatis中存在三种执行器:
-
- SIMPLE:简易执行器,默认的执行器;
- REUSE:执行重用预处理语句;
- BATCH:执行重用语句和批量更新,针对批量专用的执行器;
2.Spring IOC是什么?怎么实现的?
IoC(Ioc—Inversion of Control,即“控制反转”)是有专门一个容器来创建这些对象,即由Ioc容器来控制对 象的创建;因为由容器帮我们查找及注入依赖对象,对象只是被动的接受依赖对象,所以是反转.
注入方式:
- 接口注入
- setter
- 构造器注入
IOC容器的设计与实现有两种:BeanFactory和ApplicationContext
- 实现了BeanFactory接口的简单容器系列,只是实现了容器最基本的功能
- Applic ationContext应用上下文,作为容器的高级形态存在。除了具有基本的功能外,还增加了许多面向框架的特性,同时对应用环境做了许多适配。
3.Spring IOC里面的反射机制怎么实现的?
1.利用传入的参数获取xml文件的流,并且利用dom4j解析成Document对象
2.对于Document对象获取根元素对象
3.如果找到对应的id,相当于找到了一个Element元素,开始创建对象,先获取class属性,根据属性值利用反射建立对象.
4.遍历
5.如果属性property标签有ref属性,说明某个属性的值是一个对象,那么根据id(ref属性的值)去获取ref对应的对象,再给属性赋值.
6.返回建立的对象,如果没有对应的id,或者
Java 反射机制是在运行状态中,对于任意一个类,都能够获得这个类的所有属性和方法,对于任意一个对象都能够调用它的任意一个属性和方法。这种在运行时动态的获取信息以及动态调用对象的方法的功能称为 Java 的反射机制。
Class 类与 java.lang.reflect 类库一起对反射的概念进行了支持,该类库包含了 Field,Method,Constructor 类 (每个类都实现了 Member 接口)。这些类型的对象时由 JVM 在运行时创建的,用以表示未知类里对应的成员。
通过反射机制创建对象,在创建对象之前要获得对象的构造函数对象,通过构造函数对象创建对应类的实例。
IOC容器的初始化过程
初始化过程分成了三个过程:
- Resource定位
- BeanDefinition的载入
- 向IOC容器注册这些BeanDefinition信息。这个过程是通过BeanDefinitionRegistry接口的实现来完成的。最终注入到HashMap中去,这个hashmap就是持有beandefinition数据的。
Spring关于Bean的装配,有下面三种方式:
- 在XML中进行显示配置
- 在java中进行显示配置
- 隐式的bean发现机制和自动装配
Redis
1.redis分片,客户端请求怎么处理?
Redis的分片是指将数据分散到多个Redis实例中的方法,分片之后,每个redis拥有一部分原数据集的子集。在数据量非常大时,分片能将数据量分散到若干主机的redis实例上,进而减轻单台redis实例的压力。
- 范围分片
- 哈希分片
分片的位置:
- 客户端分片
- 代理分片
- 服务器分片
2.redis的zset底层实现
跳跃表来实现。
跳跃表相比于红黑树的优点:
- 存取速度快,节点不需要进行旋转
- 易于实现
- 支持无锁操作
3.redis和mysql的区别
- redis是key-value非关系型数据库,MySQL是关系型数据库
- redis基于内存,也可持久化,MySQL是基于磁盘
- redis读写比MySQL快的多
- redis一般用于热点数据的缓存,MySQL是存储
4.redis加锁
redis为单进程单线程模式,采用队列模式将并发访问变为串行访问,redis本身没有锁的概念,但可以用redis实现分布式锁。
- INCR
Redis Incr 命令将 key 中储存的数字值增一。 如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 INCR 操作。
- SETNX
- SET:以上两种都没有设置超时时间,SET可以实现超时时间
分布式锁的核心思想是将设置锁和超时时间、删除锁分别作为一个原子操作进行。
5.redis的淘汰策略
- volatile-lru:在设置超时时间的数据中进行lru
- volatile-ttl:在设置超时时间的数据中挑选即将过期
- volatile-random:在设置超时时间的数据中随机挑选
- allkeys-lru:所有数据的lru
- allkeys-random:所有数据的随机
- noeviction:禁止驱逐数据
6.redis无法被命中怎么办?会出现什么问题?
无法被命中:无法直接通过缓存得到想要的数据
解决方案:
- 缓存尽可能聚焦在高频访问且时效性不高的业务热点上。
- 将缓存容量设置为热点数据的容量。
- 缓存预加载。
- 设置合适的缓存淘汰策略。
7.Redis和MySQL复制和分片
复制 | 分片 | |
MySQL | 三个线程(binlog线程、I/O线程、SQL线程),目的是实现读写分离 | 水平切分、垂直切分 |
Redis | 使用RDB快照进行复制,发送期间使用缓冲区记录执行的写命令,在RDB快照发送完毕后,发送缓冲区中的写命令 | 水平切分 |
8.Redis是什么?Sorted List是什么?skiplist是什么?怎么实现的?怎么插入一个值?怎么进行查询?和其他数据结构进行对比?
9.Redis的hash和Java的map的区别