前情提要:分析代码时只会分析代码的主要算法部分。
一.众数问题。
首先,这个问题的思路是运用分治递归的思想将其划分为多个小问题,我们要输出的是众数num以及众数的个数maxCnt,a传入输入的非递减数组,n为数组的个数,将数组分为前中后三个部分,先计算中间的重复元素个数赋值为s。
public static void getMaxCnt(int a[], int n, IntHolder num, IntHolder maxCnt){
int l =0, r = 0;
int s;
int mid = n / 2;
for( l = 0;l < mid;l ++){
if(a[l] == a[mid])
break;
}
for(r = mid + 1;r < n;r++){
if(a[r] != a[mid])
break;
}
//计算重数
s = r - l;
//...
}
接着比较存储的最大众数个数和s,如果s大更新num和maxCnt,如果相等那么比较众数的大小,最后取较小的众数。
if(s > maxCnt.value){
num.value = a[mid];
maxCnt.value = s;
}
//如果重数一样则比较众数的大小
if(s == maxCnt.value){
if(num.value > a[mid]){
num.value = a[mid];
maxCnt.value = s;
}
}
最后是递归过程,看看左右两边的个数是否比已经找到的众数个数大,进行递归,如果小则不用比较。
if(l + 1 > maxCnt.value){
getMaxCnt(a,l+1,num,maxCnt);
}
if(n - r > maxCnt.value){
int [] b = new int[n-r];
for(int i = 0;i < n-r;i ++){
b[i] = a[r + i];
}
getMaxCnt(b,n-r,num,maxCnt);
}
注:这里使用IntHolder类是因为一是要在main方法里输出这两个数,其值要进行改变,二是递归过程中要进行更新。
二.半数集问题。
6半数集肯定包含他本身;
1不大于的一半 所以16;
2不大于6的一半,26;1又不大于2,所以126;
3不大于6的一半,36;1又不大于3,所以136...
观察可得,一个数的半数集等于从1+到这个数一半的半数集(奇数的话直接约)。
同样使用分治递归的方法,n为传入的数字,因为自己本身也算一个所以count = 1;
用一个数组来存储对应位置的数的半数集求6的半数集就是1+2(半数集)+3(半数集)= 6.
public static int banshu(int n){
int count = 1;
if(arr[n]>0){
return arr[n];
}
for(int i = 1;i<=n/2;i++){
count += banshu(i);
}
arr[n] = count;
return count;
}
三.重复元素排列问题。
就是排列问题,先是进入一个for循环,通过递归step+1来进行4*3*2的全排列遍历,其中为了控制在递归过程中遍历字符串中每一个字母,使用book进行存储0未遍历,1已遍历,而其中第一个if条件进行了限制将重复的排列去除。

public static void dfs(int step){
if(step == ans.length){
writeOutput("C:\\Users\\Administrator\\Desktop\\新建文件夹\\output.txt",ans);
System.out.println(Arrays.toString(ans));
}
for (int i = 0; i < a.length() ; i++) {
if(i>0&&a.charAt(i)==a.charAt(i-1)&&book[i-1]==0) continue;
if(book[i] == 0){
book[i] = 1;
ans[step] = a.charAt(i);
dfs(step+1);
book[i] = 0;
}
}
}
static String a= "";
static char []ans = new char [a.length()];
static int [] book = new int[a.length()];
public static void main(String[] args) {
// 读取输入文件
String n = readInput("C:\\Users\\Administrator\\Desktop\\新建文件夹\\input.txt");
if (n == null) {
System.out.println("无法读取输入文件,程序将终止。");
return;
}
a = n;
ans = new char[a.length()];
book = new int[a.length()];
dfs(0);
}
四.集合划分问题。
读取input里的一个数组,n为有多少个元素,m为划分为多少个集合。
1.易知特殊情况:算法的实现原理
m == 1 时,F ( 1, 1 ) = 1; //只需要分成一份
n == m 时,F ( n , m ) = 1; //当元素个数和份数一样时,每一个元素就为一份
2.一般情况:( 将问题简单化 )
a.将第 i 个元素单独放,其余 n - 1 个元素分成 m - 1 份 : F ( n -1, m - 1 ) ;
b.将第 i 个元素插入其余的 n - 1 个元素分成的 m 份中,有 m 种插入的位置:
m * F ( n -1, m );
public static int f(int n,int m){
if(m == 1 || n == m){
return 1;
}
return f(n-1,m-1) + m*f(n-1,m);
}
public static void main(String[] args) {
Integer []arr = readInput("C:\\Users\\admin\\Desktop\\新建文件夹\\input.txt");
if (arr == null) {
System.out.println("无法读取输入文件,程序将终止。");
return;
}
Integer count = f(arr[0],arr[1]);
writeOutput("C:\\Users\\admin\\Desktop\\新建文件夹\\output.txt",count);
}
五.整数因子分解问题。
该方法使用了动态规划的方法,num读取一个整数,并输出有多少个分解式。
我们用一个数组dp来存储num之前所有数的因数,再用一个for循环查找哪些数是其因数,最后将其存储在num里的分解式数量累加求和。
//整数因子分解问题,动态规划
//主要利用的原理:一个数的分解式个数等于它所有因子(除了自己)的分解式之和
public static int f(int n){
int [] dp =new int[n+1];//用来存储每个数有几种分解式
for(int i=1; i<=n; i++){
if(i == 1){
dp[i] = 1 ;//1的分解式有一个
}else {
for (int j = 1; j < i; j++) {
if (i % j == 0) {
//说明j是i的因子,并且不等于i,
//只有在这时我们才进行++操作,因为一个数的分解式个数等于它所有因子(除了自己)的分解式之和
dp[i] += dp[j];
}
}
}
}
return dp[n] ;
}
public static void main(String[] args) {
Integer num = readInput("C:\\Users\\admin\\Desktop\\新建文件夹\\input.txt");
if (num == null) {
System.out.println("无法读取输入文件,程序将终止。");
return;
}
int n = 12;
int m = f(n);
// 写入输出文件
writeOutput("C:\\Users\\admin\\Desktop\\新建文件夹\\output.txt",m);
}
273

被折叠的 条评论
为什么被折叠?



