常用算法

来源:互联网 发布:影楼行业全国数据 编辑:程序博客网 时间:2024/05/29 07:59

最大子序列之和

明白一件事,只要加了之后数为正,这个肯定在最大子序列里面,如果是小于0,那么就会出现最大子序列有可能在其里面,也有可能在未执行的子串中。

public static int maxSum(int arr[]){    int maxSum = 0,curSum = 0;    for(int i=0;i<arr.length;i++){        curSum += arr[i];        if(curSum>maxSum){            maxSum = curSum;        }        if(curSum<0){            curSum = 0;        }    }    return maxSum;}

最长公共子序列

最长公共子序列,不连续String str1 = “abcdef”;和String str2 = “abefcb”;最长公共子序列为abef。利用动态规划解决LCS问题,用二维数组记录LCS的长度,一次递归到最小的子问题。

c[i,j] = 0    i=0 or j=0c[i,j] = c[i-1,j-1] + 1      i,j>0 and Xi = Yic[i,j] = max(c[i,j-1],c[i-1,j]) i,j>0 and Xi!=Yi

// 假如返回两个字符串的最长公共子序列的长度 ,数组右下角元素就是LCS的长度

public static int[][] LCS(String str1, String str2) {          int[][] arr = new int[str1.length() + 1][str2.length() + 1];//建立二维矩阵          // 初始化边界条件          for (int i = 0; i <= str1.length(); i++) {                  arr[i][0] = 0;//每行第一列置零          }          for (int j = 0; j <= str2.length(); j++) {                  arr[0][j] = 0;//每列第一行置零          }          // 填充矩阵          for (int i = 1; i <= str1.length(); i++) {                  for (int j = 1; j <= str2.length(); j++) {                          if (str1.charAt(i - 1) == str2.charAt(j - 1)) {                                  arr[i][j] = arr[i - 1][j - 1] + 1;                          } else {                                  arr[i][j] = (arr[i - 1][j] >= arr[i][j - 1] ? arr[i - 1][j] : arr[i][j - 1]);                          }                  }          }          return matrix; }  

要是我们需要打印出最长的子序列呢,我们将上面的函数的出来的二维数组进行分析。按照三个dp公式来递归
0 0 0 0 0 0 0
0 1 1 1 1 1 1
0 1 2 2 2 2 2
0 1 2 2 2 3 3
0 1 2 2 2 3 3
0 1 2 3 3 3 3
0 1 2 3 4 4 4

public static void print(int[][] opt, String X, String Y, int i, int j) {          if (i == 0 || j == 0) {                  return;          }          if (X.charAt(i - 1) == Y.charAt(j - 1)) {                  print(opt, X, Y, i - 1, j - 1);                  System.out.print(X.charAt(i - 1));          } else if (opt[i - 1][j] >= opt[i][j]) {                  print(opt, X, Y, i - 1, j);          } else {                  print(opt, X, Y, i, j - 1);          }  }  

最长公共子串

public static int[][] LCS(String str1,String str2){    int max = 0;    char[] a = str1.toCharArray();    char[] b = str2.toCharArray();    int [][] c = new int[a.length+1][b.length+1];    for(int i=1;i<=a.length;i++){        for(int j=1;j<=b.length;j++){            if(a[i-1]==b[j-1]){                c[i][j] = c[i-1][j-1]+1;            }else{                c[i][j] = 0;            }            max = Math.max(max, c[i][j]);        }    }    return c;   }

最小栈的实现

思路参考于http://blog.jobbole.com/106940/
实现一个栈,带有出栈,入栈,取最小元素三个方法,要保证三个方法的时间复杂度都是O(1)
思路一:
创建一个整型变量min,初始值为-1,
当第一个元素入栈的时候,min为0,把唯一元素值当做做小的元素。
之后每一个新元素入栈,让新元素和min指向位置的元素比较,根据大小判断是否交换坐标
当调用getMin的时候,直接返min所指向的位置的元素就行
这个方法对三种要求都是时间和空间都为O(1),但是我们取出一个最小值后呢,就没有人来顶替他了,所以一个下标来记录最小值是不可取的。
优化方法:
新建一个栈设为B,原来的栈设为A。
当第一个元素进入栈A的时候,让新元素的下标进入B,这个唯一的元素是栈A的当前最小值
每当新的元素进入栈A的时候,比较新元素和栈A当前的最小值的大小,如果小于栈A当前的最小值,则让新元素进入B,此时B栈顶的元素就是栈A的最小值。
每当有栈A出栈的时候,如果出栈元素是栈A当前最小值,则让栈B的栈顶元素也出栈,此时栈B指向的是原来栈A的第二小元素,也是此刻最小的元素
调用getMin方法的时候,直接返回栈B的栈顶所指向的栈A的对应元素。

判断2的乘方

思路参考伯乐在线
二的乘方有个特点就是二进制全是1,那么1与0相与为0,也就是说假设N为二的乘方,那么N&N-1,结果必然是0,也就是说我们返回N&N-1是不是等于0,就可以知道这个数是不是2的乘方。

找出缺失的整数

一个无序数组里有99个不重复的正整数,范围从1到100,唯独少了一个整数,如何找出?
解法:用1到100的和减去原来有缺的1到100的整数和,得出的结果就是缺失的整数。
一个无序数组有若干个整数,范围1到100,其中99个数都出现了偶数次,只有一个整数出现了奇数次,如何找出来?
遍历整个数组,做异或运算,相同为0不同为1,所以偶数次都会被抵消为0,只有出现为奇数次的就会被留下
一个无序数组有若干个整数,范围1到100,其中99个数都出现了偶数次,只有两个个整数出现了奇数次,如何找出来?
依旧做异或运算,最终的结果就是这两个数异或的结果,但是这样两个数还是照不出来多少啊,我们先对异或的结果进行二进制分析,如果异或出来的是101,那么说明这两个数转为二进制后一个尾数是0,一个是1,那么我们可以根据二进制尾数为0的进行异或,可以找一个,同理,为1的可以找一个。当然尾数为0也可以处理,肯定异或出来的数有某一位为1,按照某一位进行分而治之,就可以解决。

辗转相除法

定律:(a>b)a与b的最大公约数等于a除以b的余数c和b之间的自大公约数。

public static int gcd(int a,int b){    int c = a+b;    if(a<b){        a = c-a;        b = c-b;    }    if(a%b==0){        return b;    }else{        return gcd(b,a%b);    }}
原创粉丝点击