題目來自劉汝佳的《算法競賽入門經典(第二版)》,下面實現代碼均爲Java
簡單枚舉
問題1:
輸入正整數, 按從小到大的順序輸出所有形如的表達式, 其中恰好爲數字的一個排列(可以有前導0),其中
解題思路:直接枚舉所有的所有排列,枚舉量爲,可以只枚舉,枚舉量下降至不到10萬
下面是枚舉的兩種解法:
解法1是直接枚舉至的所有數,枚舉會有重複元素,枚舉量爲4萬+;
解法2是遞歸枚舉(解答樹),沒有枚舉重複元素,枚舉量爲。
public class Division {
/**
* 算法1實現
* @param n 正整數
* @return 所有滿足abcde/fghij = n的abcdefghij列表
*/
private List<String> solver1(int n){
List<String> results = new ArrayList<>();
for(Integer i = 1000;i<=49999;i++){
String divisor = new String(i.toString());
if(divisor.length() < 5){
divisor = "0" + divisor;
}
String dividend = new String(new Integer(i*n).toString());
/* 如果位數共大於10 */
if(dividend.length() + divisor.length() > 10){
continue;
}
Set<Character> countSet = new HashSet<>();
for(int j = 0;j<dividend.length();j++){
countSet.add(dividend.charAt(j));
}
if(countSet.size() < 5){
continue;
}
for(int j = 0;j<divisor.length();j++){
countSet.add(divisor.charAt(j));
}
if(countSet.size() == 10){
results.add(dividend + "/" + divisor + "=" + n);
}
}
return results;
}
/**
* 算法2實現:遞歸枚舉
* @param n 輸入
* @param results 保存所有結果
* @param temp 輔助數組,記錄當前已經用過的元素
* @param cur 記錄當前已經用過的元素個數
*/
private void solver2(int n, List<String> results, Integer[] temp, int cur){
if(cur == 5){
String s = "";
Set<Integer> countSet = new HashSet<>(Arrays.asList(temp));
for(int i = 0;i<5;i++){
s += temp[i];
}
String dividend = new Integer(Integer.parseInt(s) * n).toString();
if(dividend.length() == 5){
for(int j = 0;j<dividend.length();j++){
countSet.add(Integer.parseInt(dividend.substring(j,j+1)));
}
if(countSet.size() == 10){
results.add(dividend + "/" + s + "=" + n);
}
}
}else{
for(int i = 0;i<=9;i++){
boolean flag = true;
for(int j = 0;j<cur;j++){
if(temp[j] == i){
flag = false;
break;
}
}
if(flag){
temp[cur] = i;
solver2(n, results, temp, cur+1);
}
}
}
}
/**
* 輸出結果
*/
public void solution(){
int n = 3;
/* 解法1 */
for(String s:solver1(n)){
System.out.println(s);
}
System.out.println();
/* 解法2 */
List<String> results = new ArrayList<>();
Integer[] temp = new Integer[5];
Arrays.fill(temp, -1);
solver2(n, results, temp, 0);
for(String s:results){
System.out.println(s);
}
}
public static void main(String[] args){
Division division = new Division();
division.solution();
}
}
問題2:
輸入正整數, 找到所有的正整數,使得
解題思路:首先發現時等式成立,因此只要枚舉即可,根據和判斷求出的是否爲整數
/**
* 算法實現
* @param k 正整數k
* @return 所有滿足1/k = 1/x + 1/y的x和y的列表
*/
private List<int[]> solver1(int k){
List<int[]> results = new ArrayList<>();
/* 枚舉y */
for(int y = k+1;y<=2*k;y++){
double temp = (double) k*y/(y-k);
if(temp == (int) temp){
results.add(new int[]{(int) temp, y});
}
}
return results;
}
/**
* 輸出結果
*/
public void solution(){
/* 輸入 */
int k = 12;
for(int[] result:solver1(k)){
System.out.println("1/" + result[0] + " + " + "1/" + result[1] + " = " + "1/" + k);
}
}
public static void main(String[] args){
Fractions fractions = new Fractions();
fractions.solution();
}
問題3:
輸入個元素組成的序列, 你需要找出一個乘積最大的連續子序列。 如果這個最大的乘積不是正數, 應輸出。 其中, 。
解題思路:直接枚舉起點到終點的乘積,找出最大值即可(雖然所有元素的絕對值都小於等於10,其最大乘積可能會溢出,這裏我沒管了= =)
public class MaxmiumProduct {
/**
* 算法實現
* @param a 包含所有元素
* @return 連續子序列最大乘積
*/
private long solver1(int[] a){
int n = a.length;
long[][] product = new long[n][n];
long maxProduct = 0;
for(int i = 0;i<n;i++){
long tempProduct = 1L;
for(int j = i;j<n;j++){
product[i][j] = tempProduct *= a[j];
if(maxProduct < product[i][j]){
maxProduct = product[i][j];
}
}
}
return maxProduct;
}
/**
* 輸出結果
*/
public void solution(){
/* 輸入 */
int a[] = new int[]{2, 4, -3, 2, 0, -2, -4, -8, 0, 4, 9, -5, -10} ;
System.out.println(solver1(a));
}
public static void main(String[] args){
MaxmiumProduct maxmiumProduct = new MaxmiumProduct();
maxmiumProduct.solution();
}
}
有任何問題,歡迎指出 :)