给定一数组,其大小为8个元素,数组内的数据无序。
css
public class bubbleSort {
public static void main(String[] args) {
int[] test = { 6, 3, 5, 7, 0, 4, 1, 2 };
for (int i = 0; i < test.length - 1; i++) {
for (int j = 0; j < test.length - i - 1; j++) {
if (test[j] > test[j + 1]) {
int temp = test[j];
test[j] = test[j + 1];
test[j + 1] = temp;
}
}
}
for (int k = 0; k < test.length; k++) {
System.out.println(test[k]);
}
}
}
public class selectSort {
public static void main(String[] args) {
int[] test = { 6, 3, 5, 7, 0, 4, 1, 2 };
for (int i = 0; i < test.length; i++) {
int min = i;
for (int j = i + 1; j < test.length; j++) {
if (test[min] > test[j]) {
min = j;
}
}
if (min != i) {
int temp = test[i];
test[i] = test[min];
test[min] = temp;
}
}
for (int k = 0; k < test.length; k++) {
System.out.println(test[k]);
}
}
}
public class insertSort {
public static void main(String[] args) {
int[] test = { 6, 3, 5, 7, 0, 4, 1, 2 };
for (int i = 0; i < test.length; i++) {
for (int j = i; j > 0; j--) {
if (test[j] < test[j - 1]) {
int temp = test[j];
test[j] = test[j - 1];
test[j - 1] = temp;
} else {
break;
}
}
}
for (int k = 0; k < test.length; k++) {
System.out.println(test[k]);
}
}
}
思想:不是基于比较,而是来自于桶排序,桶排序的基本思想则是把数则是arr划分为n个大小相同子区间(桶),每一个子区间各自排序,最后合并。web
经典排序算法的空间复杂度面试
经典排序算法的稳定性
稳定性:假定待排序的记录序列中,存在多个具备相同的关键字的记录,若通过排序,这些记录的相对次序保持不变,称这种排序算法是稳定的,不然称为不稳定的。算法
mid = (left + right)/2
(left+right)可能会溢出,更安全的写法:
mid = left + (right - left)/2
(1) 网页黑名单系统,垃圾邮件过滤系统,爬虫的网址判断重复系统,容忍必定程度的失误率,但对空间要求较严格 。
布隆过滤器:可精确地表明一个集合;可精确判断某一元素是否在此集合中;精确程度由用户的具体设计决定;作到100%的精确即正确是不可能的。 布隆过滤器的优点在于,利用不多的空间能够作到精确率较高。数组
举例输入:n = 100亿,p = 0.01%
1. m = - n x lnp / (ln2)
2 获得m = 19.19n 向上取整为20n,2000亿bit,约为25G。 2. k = ln2 x m/n = 0.7 x m/n = 14 所以须要14个彼此独立的哈希函数。 3. 此时失误率为(1 - e
-nk/m)
k = 0.006%,其中m = 20n, k = 14。
(2) 不用任何额外变量交换两个整数的值安全
给定整数a和b
a = a0, b = b0
a = a ^ b --> a = a0 ^ b0, b = b0;
b = a ^ b --> a = a0 ^ b0, b = a0 ^ b0 ^ b0 = a0;
a = a ^ b --> a = a0 ^ b0 ^ a0 = b0, b = a0;
(3) 给定两个32位整数a和b,返回a和b中较大的,可是不能用任何比较判断。markdown
public static int flip(int n){
return n ^ 1;
}
public static int sign(int n){
return flip((n >> 31) & 1);
}
public static int getMax(int a, int b){
int c = a - b;
int scA = sign(c);
int scB = flip(scA);
return a = a * scA + b * scB;
}
方法一可能会有问题,当a = b溢出时,会发生错误。数据结构
public static int getMax(int a, int b){
int c = a - b;
int as = sign(a); //a的符号,as == 1表示a为非负,as == 0表示a为负
int bs = sign(b); //b的符号,bs == 1表示a为非负,bs == 0表示b为负
int cs = sign(c); //a - b的符号
int difab = as ^ bs; //表示a和b是否符号不相同,不相同为1,相同为0
int sameab = flip(difab); //表示a和b是否符号相同,相同为1,不相同为0
int returnA = difab + as + sameab + cs;
int returnB = flip(returnA)
return a * returnA + b * returnB;
}
(3) 给定一个整型数组arr,其中只有一个数出现了奇数次,其余数都出现了偶数次,请打印这个数,要求时间复杂度为O(n),额外空间复杂度为O(1)。并发
注意点:n与0异或结果为n,n与n异或结果为0。 异或运算知足交换律,结合律。
(4) 给定一个整型数组arr,其中有两个数出现了奇数次,其余数都出现了偶数次,请打印这个数,要求时间复杂度为O(n),额外空间复杂度为O(1)。分布式
(5) 请设置一种加密过程,完成对明文text的加密和解密工做。
明文text,用户给定密码pw,假设密文为cipher。
cipher = text ^ pw
text = cipher ^ pw = text ^ pw ^ pw = text
若是text长度大于pw,循环使用pw与text进行按位异或。
解法:一共走13步,其中必然有5步向下,剩下的8步向右,因此一共有C13(5) = 1287.
不相邻:一共有7!种排法,其中一半的状况是A在B的左边,一半的状况是B在A的左边,因此第一种状况共有7!/2 = 2520种
相邻:A和B看做为一我的,因此第二种状况为6! = 720种
方法一:
6我的全排列6! = 720; 甲与乙相邻总数2 * 5! = 240; 甲与丙相邻总数2 * 5! = 240; 相交的状况(乙甲丙或丙甲乙)2 * 4! = 48种
720 - 240 -240 + 48 = 288
方法二:
考虑甲的位置 3 * 4! * 2 + 6 * 3! * 4 = 288
1. 首先求出8只球队分红4组比赛的方法数:7 x 5 x 3 x 1 = 105;
2. 没有两强相遇的方法数:C5(3) x A3(3) = 60;
3. (105 - 60)/105 = 3/7
方向相同不会相遇,因此(8 - 2)/8 = 3/4
男女比例依然为1:1
1. 已经有等几率随机产生一、二、三、四、5的随机函数;
2. 根据步骤1获得的结果减1,将获得f() → 0、一、二、三、4;
3. f() x 5 → 0、五、十、1五、20;
4. f() x 5 + f()→ 0、一、二、三、4...24;
注意:步骤4中的f()是分别调用的,不要化简。
5. 若是步骤4产生的数大于20,则重复地进行步骤4,直到产生的结果在0~20之间;
6. 步骤5的结果将等几率产生0~20,因此步骤5的结果%7以后等几率产生0~6;
7. 步骤6的结果加1,将等几率产生1~7.
1~3点性质是哈希函数的基础,第4点是评价一个哈希函数优劣的关键。MD5与SHA1算法都是经典的哈希函数算法,了解便可。
注意点:备份的考虑,分布式存储的设计细节,以及容灾策略;任务分配策略与任务进度跟踪的细节设计,节点状态的呈现;多用户权限的控制。
CSDN博主:常敲代码手不抖
1. 教你完全学会动态规划——入门篇
2. 教你完全学会动态规划——进阶篇
给定数组arr,arr中全部的值都为正数且不重复,每一个值表明一种面值的货币,每种面值的货币可使用任意张,再给定一个整数aim表明要找的钱数,求换钱有多少种方法。
arr = [五、十、2五、1], aim = 1000.
暴力搜索方法–>记忆搜索方法–>动态规划方法–>状态继续化简后的动态规划方法
1. 用0张5元的货币,让[10,25,1]组成剩下的1000,最终方法数记为---------------------------res1
2. 用1张5元的货币,让让[10,25,1]组成剩下的995,最终方法数记为---------------------------res2
3. 用2张5元的货币,让让[10,25,1]组成剩下的990,最终方法数记为---------------------------res3
...........................................................................................
201. 用200张5元的货币,让让[10,25,1]组成剩下的0,最终方法数记为-------------------------res201
定义递归函数:int p1(arr,index,aim),它的含义是若是用arr[index...N-1]这些面值的钱组成aim,返回总的方法数。
arr = [5、10、25、1], aim = 1000. p(index,aim) 结果表map
1. 每计算完一个p(index,aim),都将结果放入到map中,index和aim组成共同key,返回结果为value;
2. 要进入一个递归过程p(index,aim),先以index和aim注册的key在map中查询是否已经存在value,若是存在,则直接取值,若是不存在,才进行递归运算。
若是arr长度为N,生成行数为N,列数为aim + 1的矩阵dp.dp[i][j]的含义是在使用arr[0...i]货币的状况下,组成钱数j有多少种方法。
记忆搜索方法与动态规划方法的联系
1. 记忆化搜索方法就是某种形态的动态规划方法;
2. 记忆化搜索方法不关心到达某一个递归过程的路径,只是单纯地对计算过的递归过程进行记录,避免重复的递归过程;
3. 动态规划的方法则是规定好每个递归过程的计算顺序,依次进行计算,后面的计算过程严格依赖前面的计算过程;
4. 二者都是空间换时间的方法,也都有枚举的过程,区别就在于动态规划规定计算顺序,而记忆搜索不用规定。
什么是动态规划方法?
1. 其本质是利用申请的空间来记录每个暴力搜索的计算结果,下次要用结果的时候直接使用,而再也不进行重复的递归过程;
2. 动态规划规定每一种递归状态的计算顺序,依次进行计算。
动态规划方法中dp[i][j]等于以下值的累加:
dp[i-1][j]
dp[i-1][j-1*arr[i]]
dp[i-1][j-2*arr[i]]
dp[i-1][j-3*arr[i]]
以上能够化简为:dp[i][j] = dp[i-1][j-arr[i]] + dp[i-1][j]
暴力递归题目能够优化成动态规划方法的大致过程:
1. 实现暴力递归方法;
2. 在暴力搜索方法的函数中看看哪些参数能够表明递归过程;
3. 找到表明递归过程的参数以后,记忆化搜索的方法很是容易实现,利用hashmap将部分递归值进行存储;
4. 经过分析记忆化搜索的依赖路径,进而实现动态规划;
5. 根据记忆化搜索方法该出动态规划方法,进而看看是否能化简,若是能化简,还能实现时间复杂度更低的动态规划方法。