一、冒泡排序
[java] view plain
package sort.bubble;
import java.util.Random;
/**
* 依次比较相邻的两个数,将小数放在前面,大数放在后面
* 冒泡排序,具有稳定性
* 时间复杂度为O(n^2)
* 不及堆排序,快速排序O(nlogn,底数为2)
* @author liangge
*
*/
public class Main {
public static void main(String[] args) {
Random ran = new Random();
int[] sort = new int[10];
for(int i = 0 ; i < 10 ; i++){
sort[i] = ran.nextInt(50);
}
System.out.print("排序前的数组为");
for(int i : sort){
System.out.print(i+" ");
}
buddleSort(sort);
System.out.println();
System.out.print("排序后的数组为");
for(int i : sort){
System.out.print(i+" ");
}
}
/**
* 冒泡排序
* @param sort
*/
private static void buddleSort(int[] sort){
for(int i=1;i<sort.length;i++){
for(int j=0;j<sort.length-i;j++){
if(sort[j]>sort[j+1]){
int temp = sort[j+1];
sort[j+1] = sort[j];
sort[j] = temp;
}
}
}
}
}
二、选择排序
[java] view plain
package sort.select;
import java.util.Random;
/**
* 选择排序
* 每一趟从待排序的数据元素中选出最小(或最大)的一个元素,
* 顺序放在已排好序的数列的最后,直到全部待排序的数据元素排完。
* 选择排序是不稳定的排序方法。
* @author liangge
*
*/
public class Main {
public static void main(String[] args) {
Random ran = new Random();
int[] sort = new int[10];
for (int i = 0; i < 10; i++) {
sort[i] = ran.nextInt(50);
}
System.out.print("排序前的数组为");
for (int i : sort) {
System.out.print(i + " ");
}
selectSort(sort);
System.out.println();
System.out.print("排序后的数组为");
for (int i : sort) {
System.out.print(i + " ");
}
}
/**
* 选择排序
* @param sort
*/
private static void selectSort(int[] sort){
for(int i =0;i<sort.length-1;i++){
for(int j = i+1;j<sort.length;j++){
if(sort[j]<sort[i]){
int temp = sort[j];
sort[j] = sort[i];
sort[i] = temp;
}
}
}
}
}
三、快速排序
[java] view plain
package sort.quick;
/**
* 快速排序 通过一趟排序将要排序的数据分割成独立的两部分, 其中一部分的所有数据都比另外一部分的所有数据都要小,
* 然后再按此方法对这两部分数据分别进行快速排序, 整个排序过程可以递归进行,以此达到整个数据变成有序序列。
* @author liangge
*
*/
public class Main {
public static void main(String[] args) {
int[] sort = { 54, 31, 89, 33, 66, 12, 68, 20 };
System.out.print("排序前的数组为:");
for (int data : sort) {
System.out.print(data + " ");
}
System.out.println();
quickSort(sort, 0, sort.length - 1);
System.out.print("排序后的数组为:");
for (int data : sort) {
System.out.print(data + " ");
}
}
/**
* 快速排序
* @param sort 要排序的数组
* @param start 排序的开始座标
* @param end 排序的结束座标
*/
public static void quickSort(int[] sort, int start, int end) {
// 设置关键数据key为要排序数组的第一个元素,
// 即第一趟排序后,key右边的数全部比key大,key左边的数全部比key小
int key = sort[start];
// 设置数组左边的索引,往右移动判断比key大的数
int i = start;
// 设置数组右边的索引,往左移动判断比key小的数
int j = end;
// 如果左边索引比右边索引小,则还有数据没有排序
while (i < j) {
while (sort[j] > key && j > start) {
j--;
}
while (sort[i] < key && i < end) {
i++;
}
if (i < j) {
int temp = sort[i];
sort[i] = sort[j];
sort[j] = temp;
}
}
// 如果左边索引比右边索引要大,说明第一次排序完成,将sort[j]与key对换,
// 即保持了key左边的数比key小,key右边的数比key大
if (i > j) {
int temp = sort[j];
sort[j] = sort[start];
sort[start] = temp;
}
//递归调用
if (j > start && j < end) {
quickSort(sort, start, j - 1);
quickSort(sort, j + 1, end);
}
}
}
[java] view plain
/**
* 快速排序
*
* @param a
* @param low
* @param high
* voidTest
*/
public static void kuaisuSort(int[] a, int low, int high)
{
if (low >= high)
{
return;
}
if ((high - low) == 1)
{
if (a[low] > a[high])
{
swap(a, low, high);
return;
}
}
int key = a[low];
int left = low + 1;
int right = high;
while (left < right)
{
while (left < right && left <= high)// 左边向右
{
if (a[left] >= key)
{
break;
}
left++;
}
while (right >= left && right > low)
{
if (a[right] <= key)
{
break;
}
right--;
}
if (left < right)
{
swap(a, left, right);
}
}
swap(a, low, right);
kuaisuSort(a, low, right);
kuaisuSort(a, right + 1, high);
}
四、插入排序
[java] view plain
package sort.insert;
/**
* 直接插入排序
* 将一个数据插入到已经排好序的有序数据中,从而得到一个新的、个数加一的有序数据
* 算法适用于少量数据的排序,时间复杂度为O(n^2)。是稳定的排序方法。
*/
import java.util.Random;
public class DirectMain {
public static void main(String[] args) {
Random ran = new Random();
int[] sort = new int[10];
for (int i = 0; i < 10; i++) {
sort[i] = ran.nextInt(50);
}
System.out.print("排序前的数组为");
for (int i : sort) {
System.out.print(i + " ");
}
directInsertSort(sort);
System.out.println();
System.out.print("排序后的数组为");
for (int i : sort) {
System.out.print(i + " ");
}
}
/**
* 直接插入排序
*
* @param sort
*/
private static void directInsertSort(int[] sort) {
for (int i = 1; i < sort.length; i++) {
int index = i - 1;
int temp = sort[i];
while (index >= 0 && sort[index] > temp) {
sort[index + 1] = sort[index];
index--;
}
sort[index + 1] = temp;
}
}
}
顺便添加一份,差不多的
[java] view plain
public static void charuSort(int[] a)
{
int len = a.length;
for (int i = 1; i < len; i++)
{
int j;
int temp = a[i];
for (j = i; j > 0; j--)//遍历i之前的数字
{
//如果之前的数字大于后面的数字,则把大的值赋到后面
if (a[j - 1] > temp)
{
a[j] = a[j - 1];
} else
{
break;
}
}
a[j] = temp;
}
}
把上面整合起来的一份写法:
[java] view plain
/**
* 插入排序:
*
*/
public class InsertSort {
public void sort(int[] data) {
for (int i = 1; i < data.length; i++) {
for (int j = i; (j > 0) && (data[j] < data[j - 1]); j--) {
swap(data, j, j - 1);
}
}
}
private void swap(int[] data, int i, int j) {
int temp = data[i];
data[i] = data[j];
data[j] = temp;
}
}
五、顺便贴个二分搜索法
[java] view plain
package search.binary;
public class Main {
public static void main(String[] args) {
int[] sort = {1,2,3,4,5,6,7,8,9,10};
int mask = binarySearch(sort,6);
System.out.println(mask);
}
/**
* 二分搜索法,返回座标,不存在返回-1
* @param sort
* @return
*/
private static int binarySearch(int[] sort,int data){
if(data<sort[0] || data>sort[sort.length-1]){
return -1;
}
int begin = 0;
int end = sort.length;
int mid = (begin+end)/2;
while(begin <= end){
mid = (begin+end)/2;
if(data > sort[mid]){
begin = mid + 1;
}else if(data < sort[mid]){
end = mid - 1;
}else{
return mid;
}
}
return -1;
}
}
② Java面试算法题求解
看了两行看不下去了,吐槽一下。
现在某些小公司的面试官,面试题花式秀智商,一副全世界都求着他赐予工作的样子。
③ 面试官常问十大经典算法排序(用python实现)
算法是一种与语言无关的东西,更确切地说就算解决问题的思路,就是一个通用的思想的问题。代码本身不重要,算法思想才是重中之重
我们在面试的时候总会被问到一下算法,虽然算法是一些基础知识,但是难起来也会让人非常头疼。
排序算法应该算是一些简单且基础的算法,但是我们可以从简单的算法排序锻炼我们的算法思维。这里我就介绍经典十大算法用python是怎么实现的。
十大经典算法可以分为两大类:
比较排序: 通过对数组中的元素进行比较来实现排序。
非比较排序: 不通过比较来决定元素间的相对次序。
算法复杂度
冒泡排序比较简单,几乎所有语言算法都会涉及的冒泡算法。
基本原理是两两比较待排序数据的大小 ,当两个数据的次序不满足顺序条件时即进行交换,反之,则保持不变。
每次选择一个最小(大)的,直到所有元素都被输出。
将第一个元素逐个插入到前面的有序数中,直到插完所有元素为止。
从大范围到小范围进行比较-交换,是插入排序的一种,它是针对直接插入排序算法的改进。先对数据进行预处理,使其基本有序,然后再用直接插入的排序算法排序。
该算法是采用 分治法 对集合进行排序。
把长度为n的输入序列分成两个长度为n/2的子序列,对这两个子序列分别采用归并排序,最终合并成序列。
选取一个基准值,小数在左大数在在右。
利用堆这种数据结构所设计的一种排序算法。
堆是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。利用最大堆和最小堆的特性。
采用字典计数-还原的方法,找出待排序的数组中最大和最小的元素,统计数组中每个值为i的元素出现的次数,对所有的计数累加,将每个元素放在新数组依次排序。
设置一个定量的数组当作空桶;遍历输入数据,并且把数据一个一个放到对应的桶里去;对每个不是空的桶进行排序;从不是空的桶里把排好序的数据拼接起来。
元素分布在桶中:
然后,元素在每个桶中排序:
取得数组中的最大数,并取得位数;从最低位开始取每个位组成新的数组;然后进行计数排序。
上面就是我整理的十大排序算法,希望能帮助大家在算法方面知识的提升。看懂之后可以去试着自己到电脑上运行一遍。最后说一下每个排序是没有调用数据的,大家记得实操的时候要调用。
参考地址:https://www.runoob.com/w3cnote/ten-sorting-algorithm.html
④ 面试算法题:你的任务就是计算出长度为n的字符串(只包含‘A’、‘B’和‘C’),有多少个是暗黑字符串。
程序肯定不是判断一个字符串是纯洁的还是黑暗的。从现有的题目描述看,程序和题目没有关系。
题目是否不全?
⑤ 面试算法知识梳理(14) - 数字算法
面试算法知识梳理(1) - 排序算法
面试算法知识梳理(2) - 字符串算法第一部分
面试算法知识梳理(3) - 字符串算法第二部分
面试算法知识梳理(4) - 数组第一部分
面试算法知识梳理(5) - 数组第二部分
面试算法知识梳理(6) - 数组第三部分
面试算法知识梳理(7) - 数组第四部分
面试算法知识梳理(8) - 二分查找算法及其变型
面试算法知识梳理(9) - 链表算法第一部分
面试算法知识梳理(10) - 二叉查找树
面试算法知识梳理(11) - 二叉树算法第一部分
面试算法知识梳理(12) - 二叉树算法第二部分
面试算法知识梳理(13) - 二叉树算法第三部分
斐波那契数列 满足下面的通项公式,要求给出 N ,输出第 N 项的 F(N)
这里介绍两种解决办法, 循环算法 和 矩阵算法 。循环算法比较容易理解,就是从 F(0) 开始,根据通项公式,得到下一个斐波那契数列中的数字即可。
对于上面的通项公式,可以用下面的矩阵乘法的形式来表示
一个台阶总共有 n 级,如果一次可以跳 1 级,也可以跳 2 级,求总共有多少总跳法。
由于有两种跳台阶方式,因此跳 n 级台阶可以转换为下面两个问题之和:
这就和之前的斐波那契数列的通项公式相同。
这个问题,需要先总结一下规律,我们根据数字 N 的 位数 来进行分析:
那么 N>=1 时才会出现 1 ,并且出现 1 的次数为 1 次
在这种情况下,出现 1 的次数等于个位上出现 1 的次数加上十位上出现 1 的个数。
例如,如果要计算百位上 1 出现的次数,它要受到三方面的影响:百位上的数字,百位以下的数字,百位以上的数字。
对于一个二进制数,例如 1010 ,将其减 1 后得到的结果是 1001 ,也就是将最后一个 1 (倒数第二位)及其之后的 0 变成 1 , 1 变成 0 ,再将该结果与原二进制数相与,也就是 1010 & 1001 = 1000 ,那么就可以去掉最后一个 1 。
因此,如果需要计算两个数的二进制表示中有多少位是不同的,可以 先将这两个数异或 ,那么不相同的位数就会变成 1 ,之后利用上面的技巧,通过每次去掉最后一个 1 ,来 统计该结果中 1 的个数 ,就可以知道两个数的二进制表示中有多少是不同的了。
N! 的含义为 1*2*3*...*(N-1)*N ,计算 N! 的十进制表示中,末尾有多少个 0 。
N! 中能产生末尾是 0 的质数组合是 2*5 ,所以 N! 末尾的 0 的个数取决了 2 的个数和 5 的个数的最小值,有因为被 2 整除的数出现的概率大于 5 ,因此 5 出现的次数就是 N! 末尾 0 的个数。因此,该问题就转换成为计算从 1~N ,每个数可以贡献 5 的个数,也就是每个数除以 5 的值。
上面的解法需要从 1 到 N 遍历每一个数,当然还有更加简便的方法。以 26! 为例,贡献 5 的数有 5、10、15、20、25 ,一共贡献了 6 个 5 ,可以理解为 5 的倍数 5、10、15、20、25 贡献了一个 5 ,而 25 的倍数又贡献了一个 5 ,得到下面的公式:
首先,让我们换一个角度考虑,其实这个问题就是求解二进制表示中从最低位开始 0 的个数,因为二进制最低位为 0 代表的是偶数,能够被 2 整除,所以质因数 2 的个数就是二进制表示中最低位 1 后面的 0 的个数。
因此,我们的实现这就和上面 2.7 中求解质因数 5 的个数是一样的。
最大公约数 的定义为 两个或多个整数的共有约数中最大的一个 。这里采用的是 更相止损法 ,其操作步骤为:
则第一步中约掉的若干个 2 与第二步中等数的乘积就是所求的最大公约数。
有限小数或者无限循环小数都可以转化为分数,例如:
在 http://blog.csdn.net/flyfish1986/article/details/47783545 这边文章中,详细地描述了该题的解决思路,核心思想就是将原小数分为 有限部分 和 无限循环小数 部分,对于这两部分别进行处理。
⑥ 大公司笔试面试有哪些经典算法题目
大公司的笔试面试一般是针对你所面试的岗位进行一些专业知识的考核,不会出现想考公员里面的行测似得,当然也有哪些逆向思维的计算题。
⑦ A/B Test基本原理
一、引入
ABTest,就是做一个测试,在产品设计场景中,为同一个产品目标制定两个方案(比如两个页面一个用这个文案另一个用那个文案,一个用红色的按钮、另一个用蓝色),让一部分用户使用A方案,另一部分用户使用B方案,然后利用埋点可以对用户点击行为数据进行采集,并通过统计引擎分析结构化的日志数据,计算相关指标,一般是点击率、转化率、CTR(点击次数/展示量)等,进行假设检验,从而得出那个方案更好
ABtest原理很简单。ABtest的难度主要在开发上:开发新版本、进行测试、测试数据回传保存
二、AB Test步骤
ABtest本质上是一个两总体假设检验问题,要检验A、B两个版本是否有显着区别。
两总体假设检验步骤:
第一步:确定对象和指标。明确要检验的A、B两个对象,版本。以及要检验的指标,是CTR,还是客单价,ARPU
第二步:给出原假设/备择假设
第三步:选择检验统计量,t 还是F?(t是总体方差未知或小样本,用样本方差代替总体方差。F是总体方差或大样本)
第四步:埋点,获取数据。计算统计量,明确A,B版本是否有显着区别。p值小于显着性水平0.05则推翻原假设
确定目标 --> 确定最小样本量 --> 确认流量分割方案 --> 实验上线 --> 规则校验 --> 数据收集 --> 效果检验
三、AB Test例子
某电商平台,想提升用户客单价,运营部门做了两套A、B激励方案,想将流量分成相同的两批测试下效果。已选出两组各12名用户,测试用户客单价如下
H0:方案A客单价均值=方案B客单价均值
H1:两者不相等
解读结论
既然方案A与方案B不同,A的均值又高于B,那么就认为A更好
三、AB Test的局限性
AB Test要求数据充足、开发资源充足的时候,才能完美落地
且AB测试得到的结果是更优的方案,而不是最优,所以只能作为一种验证性的工具和方法,要得到最优,不可能通过做很多次AB Test,这样成本太大
A/B测试只有在 你要测的KPI指标 可以被电脑量化 时适用,对于声誉,公关等不适用
四、面试题
Q1:什么场景可以做AB测试?
产品迭代场景:界面优化、增加功能
策略优化场景:运营策略优化,算法策略优化(推荐算法)
检验场景:新功能推出,30天内的DAU增加了,那么要通过假设检验来测试这个结果是否显着
Q2:为什么要进行ABtest
APP想要存活及增长,精细化运营就变成了必须。往往产品的认知并不是用户的认知,所以我们需要去测试,去实验。类似于医学中的“双盲实验”
Q3:AB Test需要多大的样本?AB Test需要做多久是如何确定的?如果计划做20天,第10天时感觉结果显着,能不能停止测试?
样本量 计算公式:
Q4:做AB实验的时候,数据对比上涨25%,判定为效果显着,但上线后效果不好,为什么?
样本量不足,结果是随机波动导致
实验时间太短,用户由于新鲜感表现出不可持续的行为
实验人群不等于上线人群
外部环境变化,比如打车场景下,下雨和下雪会导致订单量激增
Q5:谈谈第一类错误,第二类错误
互联网产品案例中,第一类错误(拒真错误):本来是一个好的产品,它本来可以给我们带来收益,但是由于我们统计的误差,导致我们误认为它并不能给我们带来收益。
第二类错误代表的是一个功能改动,本来不能给我们带来任何收益,但是我们却误认为它能够给我们带来收益。
Q6:流量分割有哪两种方式?
Q7:假设检验如何选取统计量?
Q7:ABTest有哪些注意事项?
一些效应
① 网络效应:
主要是因为对照组和实验组在一个社交网络导致。如果微信改动了某一个功能,这个功能让实验组用户更加活跃,发更多朋友圈。但是实验组用户的好友可能在对照组,实验组发的多,对照组用户可能就刷朋友圈刷的多,所以本质上对照组用户也受到了新功能的影响,那么ABTest就不再能很好的检测出相应的效果
解决办法:从地理上隔绝用户
② 学习效应:
主要是用户的好奇心理导致。比如产品将某个按钮从暗色调成亮色。很多用户刚刚看到,会有个新奇心里,去点击该按钮,导致按钮点击率在一段时间内上涨,但是长时间来看,点击率可能又会恢复到原有水平
解决方法:一是把时间拉长。二是只看新用户的数据
Q7:如果样本量不足该怎么办
只能通过拉长时间周期,通过累计样本量来进行比较
Q8:是否需要上线第一天就开始看效果?
在做AB测试时,尽量设定一个测试生效期,这一般是用户的一个活跃周期。如用户活跃间隔是7天,那么生效期为7天,如果是一个机酒app,用户活跃间隔是30天,那生效期为30天
BOUNUS:
ABtest实验可以分成两种,客户端client实验和服务端server实验
客户端实验一般来说只是UI上的实验,纯粹是展示端的策略;
而服务端的实验是返回给client数据的内容做实验,比如推荐的策略,算法策略等
⑧ 经典C语言面试算法题
经典C语言面试算法题
1.写一个函数,它的原形是int continumax(char *outputstr,char *intputstr)
功能:
在字符串中找出连续最长的数字串,并把这个串的长度返回,并把这个最长数字串付给其中一个函数参数outputstr所指内存。例如:"abcd12345ed125ss123456789"的首地址传给intputstr后,函数将返回
9,outputstr所指的值为123456789。
#include
#include
#include
int FindMax_NumStr(char *outputstr,char *inputstr)
{
char *in = inputstr,*out = outputstr,*temp;
char *final;
int count = 0;
int maxlen = 0;
int i;
while(*in!='