算法分析与设计总复习
前言
提示:转载链接☟
算法复习
一、算法引论
1、算法的四个性质
输入:零个或多个
输出:至少一个
确定性:每条指令清晰无歧义
有限性:每条指令执行次数有限,且执行时间有限
2、程序
程序是算法用某种程序设计语言的具体实现
程序不一定满足有限性
3、描述算法三种形式
自然语言:易懂但易产生歧义
程序流程图:直观形象,但难以绘制及修改
伪代码:易懂易改易转化为程序代码,但难以规范
4、算法复杂性分析
算法复杂性高低体现在运行该算法所需要的计算机资源的多少上
算法的时间复杂度T(n),所需的时间资源
算法的空间复杂度S(n),所需的空间资源
算法分析:分析算法复杂度的过程
空间复杂度分析较为简单,一般分析时间复杂度
一般用空间换时间
5、算法复杂性在渐进意义下的阶(记号):
O:大于等于当前函数(f)的函数(g)(上界),f的阶不高于g的阶
Ω:小于等于当前函数(f)的函数(g)(下界),f的阶不低于g的阶
θ:同阶
o:f的阶低于g的阶
O(1) < O(logn) < O(n) < O(nlogn) < O(n^2) < O(n^3) < O(2^n) < O(n!)
常见使用O
二、递归
1、知识点
递归调用:一个函数的调用过程中直接或间接的调用该函数本身,称为函数>的递归调用,这种函数称为递归函数
直接递归:p->p
间接递归:p->q,q->p
递归要素:递归表达式(递归方程),递归结束条件(边界条件)
优点:结构清晰,可读性强,可证明
缺点:算法运行效率低
可用递归解决问题应满足的条件:
问题可转化为一个或多个子问题进行求解,且子问题和原问题求解方法相同,仅数量规模不同。
必须有结束递归的条件终止递归。
何时使用递归:
定义是递归的(阶乘,斐波那契数列)
数据结构是递归的(二叉树,单链表)
问题求解方法是递归的(hanoi塔,回溯法)
2、阶乘函数
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc = new Scanner(System.in);
while(sc.hasNext()){
int result = sc.nextInt();
System.out.println(f(result));
}
}
public static int f(int n) {
// TODO Auto-generated method stub
return n==0?1:f(n-1)*n;
}
}
3、斐波那契数列
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc = new Scanner(System.in);
while(sc.hasNext()){
int result = sc.nextInt();
System.out.println(fibonacci(result));
}
}
public static int fibonacci(int n) {
// TODO Auto-generated method stub
return (n==0||n==1)?1:fibonacci(n-1)+fibonacci(n-2);
}
}
4、汉诺塔问题
import java.util.Scanner;
public class Main {
static int step=0;
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc = new Scanner(System.in);
while(sc.hasNext()){
step=0;
int n = sc.nextInt();
hanoi(n,'A','B','C');
}
}
public static void hanoi(int n,char a,char b,char c) {
// TODO Auto-generated method stub
if(n>0){
hanoi(n-1,a,c,b);//将第n-1个从A经过C运到B
move(n,a,c); //将第n个从A移到C(上面的在B,可以直接移动)
hanoi(n-1,b,a,c);//将第n-1个从B经过A运到C
}
}
public static void move(int n, char a, char c) {
// TODO Auto-generated method stub
System.out.println(++step+" : "+n+" from "+a+" to "+c);
}
}
5、全排列问题
import java.util.Scanner;
public class Main {
static int total = 0;
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc = new Scanner(System.in);
while(sc.hasNext()){
int n = sc.nextInt();
int[] a = new int[n+1];
total = 0;
for(int i=1;i<=n;i++)
a[i] = i;
perm(1,n,a);
System.out.println("总共有" + total + "种");
}
}
public static void perm(int k, int n,int[] a) {
// TODO Auto-generated method stub
if(k==n){
for(int i=1;i<=n;i++){
System.out.print(a[i]+" ");
}
System.out.println();
total++;
}
else {
//轮流做第k个
for(int i=k;i<=n;i++){
int t=a[i];a[i]=a[k];a[k]=t;
perm(k+1,n,a);
//排序完之后需要恢复原来的数组,方便下一个元素继续
t=a[i];a[i]=a[k];a[k]=t;
}
}
}
}
6、整数划分问题
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc = new Scanner(System.in);
while(sc.hasNext()){
int n = sc.nextInt();
System.out.println(q(n,n));
}
}
public static int q(int n, int m) {
// TODO Auto-generated method stub
if(n==1||m==1) return 1;
if(n<m) return q(n,n);
if(n==m) return q(n,m-1)+1;
return q(n-m,m)+q(n,m-1);
}
}
三、分治
1、知识点
定义:将一个难以直接解决的大问题,分割成一些规模较小的相同问题,以便各个击破,分而治之
自顶向下分解,自底向上求解
可解决的问题:
规模缩小到一定程度
具有最优子结构性质(问题可分解为若干个规模较小的相同问题)
子问题的解可合并为该问题的解
各个子问题相互独立
用分治法设计算法时,最好使子问题规模大致相同(平衡子问题思想)
分治法时间复杂度分析(主定理)
T(n) = aT(n/b) + f(n) //将规模为n的问题分解为a个大小为n/b的子问题,f(n)是合并为原问题的解所需要的时间。
= a*[aT(n/b^2) + f(n/b) ] + f(n)
= a2*T(n/b2) + a*f(n/b) + f(n)
=…
总结:①当f(n)=c,a=1时 T(n) = O(logbn)
当f(n)=c,a!=1时 T(n) = O(n^(logba))
②当f(n)=cn,a<b时 T(n) = O(n)
当f(n)=cn,a=b时 T(n) = O(nlogbn)
当f(n)=cn,a>b时 T(n) = O(n^(logba))
2、二分查找
import java.util.Scanner;
public class Main{
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc=new Scanner(System.in);
while(sc.hasNext()){
int n = sc.nextInt();
int key = sc.nextInt();
int[] a = new int[n];
for(int i=0;i<n;i++){
a[i] = sc.nextInt();
}
int rel = binarySearch(a,key,0,n-1);
if(rel == -1)
System.out.println("No Solution");
else
System.out.println(rel+1);
}
}
public static int binarySearch(int[] a,int key, int low, int high) {
// TODO Auto-generated method stub
if(low>high) {
return -1;
}
int mid = (low+high)/2;
if(key==a[mid]) {
return mid;
}
else if(key<a[mid])
return binarySearch(a,key,low,mid-1);
else
return binarySearch(a,key,mid+1,high);
}
}
3、快速排序
最好情况:T(n) = O(nlogn)
最坏情况:T(n) = O(nl^2)
平均情况:T(n) = O(nlogn)
稳定性:不稳定
import java.util.Scanner;
public class Main{
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc=new Scanner(System.in);
while(sc.hasNext()){
int n = sc.nextInt();
int[] a = new int[n];
for(int i=0;i<n;i++){
a[i] = sc.nextInt();
}
quickSort(a,0,n-1);
for(int i = 0;i<n;i++) {
System.out.print(a[i]+" ");
}
System.out.println();
}
}
//分区方法 返回分区的基准位置
public static int partition(int[] a,int p,int q) {
int x = a[p];
int i = p,j;
for(j = p+1;j<=q;j++) {
if(a[j]<=x) {
i++;
swap(a,i,j);
}
}
swap(a,p,i);
return i;
}
//交换方法
public static void swap(int[] a,int i,int j) {
int x = a[i];
a[i] = a[j];
a[j] = x;
}
//先分区 再递归
public static void quickSort(int[] a,int p,int q) {
if(p<q) {
int r = partition(a,p,q);
quickSort(a,p,r-1);
quickSort(a,r+1,q);
}
}
}
4、增加随机函数后的快速排序
时间复杂度:T(n) = O(nlogn)
import java.util.Random;
import java.util.Scanner;
public class Main{
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc=new Scanner(System.in);
while(sc.hasNext()){
int n = sc.nextInt();
int[] a = new int[n];
for(int i=0;i<n;i++){
a[i] = sc.nextInt();
}
quickSort(a,0,n-1);
for(int i = 0;i<n;i++) {
System.out.print(a[i]+" ");
}
System.out.println();
}
}
public static int Random_partition(int[] a,int p,int q) {
Random ran = new Random();
int i = ran.nextInt(q-p+1)+p;
swap(a,i,p);
return partition(a,p,q);
}
public static int partition(int[] a,int p,int q) {
int x = a[p];
int i = p,j;
for(j = p+1;j<=q;j++) {
if(a[j]<=x) {
i++;
swap(a,i,j);
}
}
swap(a,p,i);
return i;
}
public static void swap(int[] a,int i,int j) {
int x = a[i];
a[i] = a[j];
a[j] = x;
}
public static void quickSort(int[] a,int p,int q) {
if(p<q) {
int r = Random_partition(a,p,q);
quickSort(a,p,r-1);
quickSort(a,r+1,q);
}
}
}
5、随即分区查找第k小元素
时间复杂度:T(n) = O(n)
import java.util.Random;
import java.util.Scanner;
public class Main{
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc=new Scanner(System.in);
while(sc.hasNext()){
int n = sc.nextInt();
int[] a = new int[n];
for(int i=0;i<n;i++){
a[i] = sc.nextInt();
}
int k = sc.nextInt();
System.out.println(randomizedSelect(a,0,n-1,k));
}
}
public static int randomizedPartition(int[] a,int p,int q) {
int i = random(p,q);
swap(a,p,i);
return partition(a,p,q);
}
public static int random(int p,int q) {
Random ran = new Random();
return ran.nextInt()%(q-p+1)+p;
}
public static int partition(int[] a,int p,int q) {
int x = a[p];
int i = p,j;
for(j = p+1;j<=q;j++) {
if(a[j]<=x) {
i++;
swap(a,i,j);
}
}
swap(a,p,i);
return i;
}
public static void swap(int[] a,int i,int j) {
int x = a[i];
a[i] = a[j];
a[j] = x;
}
public static int randomizedSelect(int[] a,int p,int q,int k) {
if(p == q) {
return a[p];
}
int i = randomizedPartition(a,p,q);
int j = i-p+1;
return k<=j?randomizedSelect(a,p,i,k):randomizedSelect(a,i+1,q,k-j);
}
}
6、归并排序
最坏情况:T(n) = O(nlogn)
平均情况:T(n) = O(nlogn)
空间复杂度:O(n)
稳定性:稳定(高效算法中唯一稳定的排序算法)
import java.util.Scanner;
public class Main{
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc=new Scanner(System.in);
while(sc.hasNext()){
int n = sc.nextInt();
int[] a = new int[n];
int[] b = new int[n];
for(int i = 0;i<n;i++){
a[i] = sc.nextInt();
}
mergeSort(a,b,0,n-1);
for(int i = 0;i<n;i++) {
System.out.print(a[i] + " ");
}
System.out.println();
}
}
public static void merge(int[] a,int[] b,int l,int m,int h) {
//分区左边是i到m,右边是j到h,k是用来记录b数组的记录位置下标的,所以是从l到h
int i = l,j = m+1,k = l;
while(i<=m&&j<=h) {
if(a[i] <= a[j]) {
b[k] = a[i];
k++;
i++;
}
else {
b[k] = a[j];
k++;
j++;
}
}
while(i<=m) {
b[k] = a[i];
k++;
i++;
}
while(j<=h) {
b[k] = a[j];
k++;
j++;
}
}
public static void mergeSort(int[] a,int[] b,int l,int h) {
if(l<h) {
int m = (l+h)/2;
mergeSort(a,b,l,m);
mergeSort(a,b,m+1,h);
merge(a,b,l,m,h);
for(int i = l;i<=h;i++) {
a[i] = b[i];
}
}
}
}
7、棋盘覆盖
import java.util.Scanner;
public class Main{
static int flag;
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc=new Scanner(System.in);
while(sc.hasNext()){
int n = sc.nextInt();
int[][] a = new int[n][n];
int dr = sc.nextInt();
int dc = sc.nextInt();
flag = 1;
a[dr][dc] = -1;
// for(int i = 0;i<n;i++) {
// for(int j = 0;j<n;j++) {
// a[i][j] = sc.nextInt();
// if(a[i][j] == -1) {
// dr = i;
// dc = j;
// }
// }
// }
chessBoard(a,0,0,dr,dc,n);
for(int i = 0;i<n;i++) {
for(int j = 0;j<n;j++) {
System.out.print(a[i][j] +" ");
}
System.out.println();
}
System.out.println();
}
}
public static void chessBoard(int[][] a,int tr,int tc,int dr,int dc,int n) {
if(n == 1) {
return ;
}
int t = flag++;
int s = n/2;
//左上
if(dr<tr+s&&dc<tc+s) {
chessBoard(a,tr,tc,dr,dc,s);
}
else {
a[tr+s-1][tc+s-1] = t;
chessBoard(a,tr,tc,tr+s-1,tc+s-1,s);
}
//左下
if(dr>=tr+s&&dc<tc+s) {
chessBoard(a,tr+s,tc,dr,dc,s);
}
else {
a[tr+s][tc+s-1] = t;
chessBoard(a,tr+s,tc,tr+s,tc+s-1,s);
}
//右上
if(dr<tr+s&&dc>=tc+s)
chessBoard(a,tr,tc+s,dr,dc,s);
else
{
a[tr+s-1][tc+s]=t;
chessBoard(a,tr,tc+s,tr+s-1,tc+s,s);
}
//右下
if(dr>=tr+s&&dc>=tc+s)
chessBoard(a,tr+s,tc+s,dr,dc,s);
else
{
a[tr+s][tc+s]=t;
chessBoard(a,tr+s,tc+s,tr+s,tc+s,s);
}
}
}
8、大整数乘法
T(n) = 4T(n/2)+O(n^2) = O(n^2)
改进后进行3次乘法运算 T(n) =O(n^log3) = O(n^1.59)
import java.util.Random;
import java.util.Scanner;
public class Main{
static int flag;
static int[][] a = new int[100][100];
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc=new Scanner(System.in);
while(sc.hasNext()){
flag=1;int dr = 0,dc=0;
long x = sc.nextLong();
long y = sc.nextLong();
int ss=sign(x)*sign(y);
x=Math.abs(x);y=Math.abs(y);
int n=length(x);
System.out.println(ss*solve(x,y,n));
}
}
private static long solve(long x, long y, int n) {
// TODO Auto-generated method stub
if(x==0||y==0) return 0;
else if(n==1) return x*y;
else
{
long a=(long)(x/Math.pow(10,n/2));
long b=(x%(long)Math.pow(10,n/2));
long c=(long)(y/Math.pow(10,n/2));
long d=(y%(long)Math.pow(10,n/2));
long ac=solve(a,c,n/2);
long bd=solve(b,d,n/2);
long ab_dc=solve(a-b,d-c,n/2);
return (long)(ac*Math.pow(10,n)+(ab_dc+ac+bd)*Math.pow(10,n/2)+bd);
//xy=ac*10^n+((a-b)(d-c)+ac+bd)*10^(n/2)+bd
}
}
private static int length(long x) {
// TODO Auto-generated method stub
x = x>0?x:-x;
return String.valueOf(x).length();
}
private static int sign(long x) {
// TODO Auto-generated method stub
return x>0? 1:-1;
}
}
9、矩阵乘法
T(n) = 8T(n/2)+O(n^2) = O(n^3)
改进后进行7次乘法运算 T(n) =O(n^log7) = O(n^2.81)
四、动态规划
1、知识点
1.动态规划解决的问题经分解后往往不是互相独立的
2.拒绝重复
通过一个表来记录所有以解决的子问题的解,便于出现重复时减少计算
3.设计动态规划算法的步骤:
找出最优解的性质,并刻画其结构特征
递归的定义最优值
以自底向上的方式计算出最优值(填表法)
4.动态规划的两个要素:
最优子结构:问题最优解包含了其子问题的最优解,利用问题最优子结构性质,以自底向上的方式递归的从子问题的最优解逐步构造出整个问题的最优解。分析最优子结构性质方法:假设由问题最优解导出的子问题解不是最优的,再设法说明在这个假设下可构造出比原问题最优解更好的解,从而导致矛盾。
重叠子问题:在用递归算法自顶向下求解问题时,子问题并不总是新问题,有些子问题被重复计算多次。
5.递归方式:
自底向上:动态规划法,填表法
自顶向下:备忘录法,记忆化搜索,查表法
6.动态规划法的变形-备忘录法
又称为记忆化搜索,查表法,自顶向下求解问题int solve(){ if(备忘录中包含子问题解) return 备忘录中的值; else 递归求解; }
7.备忘录法的控制结构与直接递归方法的控制结构相同,区别是备忘录法为每个解过的子问题建立备忘录以备需要时查看,避免相同问题重复求解
2、数字三角形
1)递归法
二叉树,共有2^(n-1)条路经
时间复杂度:T(n) =O( 2^n)
import java.util.Scanner;
public class Main{
static int[][] a = new int[100][100];
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc=new Scanner(System.in);
while(sc.hasNext()){
int n = sc.nextInt();
for(int i=0;i<n;i++){
for(int j=0;j<=i;j++){
a[i][j]=sc.nextInt();
}
}
System.out.println(fun(0,0,n));
}
}
private static int fun(int i,int j,int n) {
// TODO Auto-generated method stub
if(i==n) return 0;
else{
return a[i][j]+max(fun(i+1,j,n),fun(i+1,j+1,n));
}
}
private static int max(int x,int y)
{
return x>y? x:y;
}
}
2)备忘录法
时间复杂度:T(n) =O( 2^n)
import java.util.Scanner;
public class Main{
static int[][] a = new int[100][100];
static int[][] b = new int[100][100];
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc=new Scanner(System.in);
while(sc.hasNext()){
int n = sc.nextInt();
for(int i=0;i<n;i++){
for(int j=0;j<=i;j++){
a[i][j]=sc.nextInt();
b[i][j]=-1;
}
}
System.out.println(fun(0,0,n));
}
}
private static int fun(int i,int j,int n) {
// TODO Auto-generated method stub
if(i==n) return 0;
else{
if(b[i][j]==-1)
b[i][j]=a[i][j]+max(fun(i+1,j,n),fun(i+1,j+1,n));
return b[i][j];
}
}
private static int max(int x,int y)
{
return x>y? x:y;
}
}
3)动态规划法
方法一:
b[i][j]表示从点(i,j)到达最后一层最大路径和
b[i][j]=a[i][j] 当i=n-1时,即到达最后一层
b[i][j]=max{b[i+1][j],b[i+1][j+1]} 当0<=i<n-1时
import java.util.Scanner;
public class Main{
static int[][] a = new int[100][100];
static int[][] b = new int[100][100];
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc=new Scanner(System.in);
while(sc.hasNext()){
int n = sc.nextInt();
for(int i=0;i<n;i++){
for(int j=0;j<=i;j++){
a[i][j]=sc.nextInt();
}
}
fun(n);
System.out.println(b[0][0]);
}
}
private static void fun(int n) {
// TODO Auto-generated method stub
for(int j=0;j<n;j++)
b[n-1][j]=a[n-1][j];
for(int i=n-2;i>=0;i--){
for(int j=0;j<=i;j++){
b[i][j]=a[i][j]+max(b[i+1][j],b[i+1][j+1]);
}
}
}
private static int max(int x,int y)
{
return x>y? x:y;
}
}
方法二:
b[i][j]表示从点(0,0)到达点(i,j)的最大路径和
b[i][j]=a[i][j] 当i=0时,即顶层
b[i][j]=max{b[i-1][j],b[i-1][j-1]} 当0<i<n时
import java.util.Scanner;
public class Main{
static int[][] a = new int[100][100];
static int[][] b = new int[100][100];
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc=new Scanner(System.in);
while(sc.hasNext()){
int n = sc.nextInt();
for(int i=1;i<=n;i++){
for(int j=1;j<=i;j++){
a[i][j]=sc.nextInt();
}
}
fun(n);
int max=0;
for(int i=1;i<=n;i++){
if(b[n][i]>max)
max=b[n][i];
}
System.out.println(max);
}
}
private static void fun(int n) {
// TODO Auto-generated method stub
for(int j=0;j<=n;j++)
b[1][j]=a[1][j];
for(int i=2;i<=n;i++){
for(int j=1;j<=i;j++){
b[i][j]=a[i][j]+max(b[i-1][j],b[i-1][j-1]);
}
}
}
private static int max(int x,int y)
{
return x>y? x:y;
}
}
3、最长公共子序列
1)递归法
时间复杂度:T(n) = O(m*n)
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
// TODO Auto-generated method stub
String a = new String();
String b = new String();
Scanner scan = new Scanner(System.in);
a = scan.nextLine();
b = scan.nextLine();
System.out.println(fun(a,b,a.length()-1,b.length()-1));
}
public static int fun(String a,String b,int i,int j) {
if (i < 0 ||j < 0) {
return 0;
}
if (a.charAt(i) == b.charAt(j)) {
return fun(a,b,i-1,j-1) + 1;
}
else {
return max(fun(a,b,i,j-1),fun(a,b,i-1,j));
}
}
public static int max(int x,int y) {
return x > y ? x:y;
}
}
2)备忘录法
时间复杂度:T(n) = O(m*n)
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
// TODO Auto-generated method stub
String a = new String();
String b = new String();
Scanner scan = new Scanner(System.in);
a = scan.nextLine();
b = scan.nextLine();
int[][] c = new int[a.length()][b.length()];
for (int i = 0;i < a.length();i++) {
for (int j = 0;j < b.length();j++) {
c[i][j] = -1;
}
}
System.out.println(fun(a,b,a.length()-1,b.length()-1, c));
}
public static int fun(String a,String b,int i,int j,int[][] c) {
if (i < 0 ||j < 0) {
return 0;
}
if (c[i][j] == -1) {
if (a.charAt(i) == b.charAt(j)) {
c[i][j] = fun(a,b,i-1,j-1,c) + 1;
}
else {
c[i][j] = max(fun(a,b,i,j-1,c),fun(a,b,i-1,j,c));
}
}
return c[i][j];
}
public static int max(int x,int y) {
return x > y ? x:y;
}
}
3)动态规划法
两层循环时间复杂度: T(n) = O(m*n)
import java.util.Scanner;
public class Main{
static int[][] c = new int[100][100];
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc=new Scanner(System.in);
while(sc.hasNext()){
String x = sc.next();
String y = sc.next();
char a[] = x.toCharArray();
char b[] = y.toCharArray();
System.out.println(fun(a,b));
}
}
private static int fun(char[] a, char[] b) {
// TODO Auto-generated method stub
for(int i=0;i<=a.length;i++) c[i][0]=0;
for(int j=0;j<=b.length;j++) c[0][j]=0;
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 if(c[i-1][j]>c[i][j-1]){
c[i][j]=c[i-1][j];
}
else{
c[i][j]=c[i][j-1];
}
}
}
return c[a.length][b.length];
}
}
4、最长公共连续子串
动态规划法
两层循环 T(n) = O(m*n)
import java.util.Scanner;
public class Main{
static int[][] c = new int[100][100];
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc=new Scanner(System.in);
while(sc.hasNext()){
String x = sc.next();
String y = sc.next();
char a[] = x.toCharArray();
char b[] = y.toCharArray();
fun(a,b);
}
}
private static void fun(char[] a, char[] b) {
// TODO Auto-generated method stub
for(int i=0;i<a.length;i++){
if(a[i]==b[0]) c[i][0]=1;
else c[i][0]=0;
}
for(int j=0;j<b.length;j++){
if(a[0]==b[j]) c[0][j]=1;
else c[0][j]=0;
}
for(int i=1;i<a.length;i++){
for(int j=1;j<b.length;j++){
if(a[i]==b[j]) c[i][j]=c[i-1][j-1]+1;
else c[i][j]=0;
}
}
int max=0,ii=0,jj=0;
for(int i=0;i<a.length;i++){
for(int j=0;j<b.length;j++){
if(c[i][j]>max){
max=c[i][j];
ii=i;
jj=j;
}
}
}
System.out.println(max);
for(int i=ii-max+1;i<=ii;i++)
System.out.print(a[i]);
System.out.println();
}
}
5、最大字段和
1)穷举法
时间复杂度:T(n) = O(n^3)
import java.util.Scanner;
public class Main{
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner scan = new Scanner(System.in);
int n = scan.nextInt();
int[] a = new int[n];
for (int i = 0;i < n;i++) {
a[i] = scan.nextInt();
}
int max = 0;
for (int i = 0;i < n;i++) {
for (int j = 0;j < n;j++) {
int sum = 0;
for (int k = i;k <= j;k++) {
sum += a[k];
}
if (max < sum) {
max = sum;
}
}
}
System.out.println(max);
}
}
2)穷举法改进
时间复杂度:T(n) = O(n^2)
import java.util.Scanner;
public class Main{
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner scan = new Scanner(System.in);
int n = scan.nextInt();
int[] a = new int[n];
for (int i = 0;i < n;i++) {
a[i] = scan.nextInt();
}
int max = 0;
for (int i = 0;i < n;i++) {
int sum = 0;
for (int j = i;j < n;j++) {
sum += a[j];
if (max < sum) {
max = sum;
}
}
}
System.out.println(max);
}
}
3)动态规划法
时间复杂度:T(n) = O(n)
空间复杂度:S(n)=O(n)
设b[j]为以a[j]作为最后一个元素时的最大子段和,故最大子段和为max{b[j]}
当j=0时,b[j]=a[j]
当j>0时,若b[j-1]<0;b[j]=a[j];若b[j-1]>=0时,b[j]=b[j-1]+a[j]
import java.util.Scanner;
public class Main {
static int[] a = new int [100];
static int[] b = new int [100];
static int[] c = new int [100];
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc = new Scanner(System.in);
while(sc.hasNext()){
int n = sc.nextInt();
for(int i=0;i<n;i++){
a[i] = sc.nextInt();
}
int maxSum = fun(n);
System.out.println(maxSum);
fun2(maxSum,n);
}
}
private static void fun2(int maxSum, int n) {
// TODO Auto-generated method stub
int max_index = 0,min_index = 0;
for(int i=0;i<n;i++){
if(b[i]==maxSum){
max_index = i;
break;
}
}
for(int i=max_index;i>=0;i--){
maxSum-=a[i];
if(maxSum==0){
min_index=i;
break;
}
}
System.out.println((min_index+1)+" "+(max_index+1));
}
private static int fun(int n) {
// TODO Auto-generated method stub
b[0]=a[0];
int max = b[0];
for(int i=1;i<n;i++){
if(b[i-1]>=0) b[i]=b[i-1]+a[i];
else b[i]=a[i];
if(b[i]>max) max=b[i];
}
return max;
}
}
待续。。。