【算法设计与分析(课后答案)】递归

1. 求解n阶螺旋矩阵问题

【问题描述】 创建n阶螺旋矩阵并输出。

【输入描述】输入包含多个测试用例,每个测试用例为一行,包含一个正整数n(1≤n≤50),以输入0表示结束。
【输出描述】每个测试用例输出n行,每行包括n个整数,整数之间用一个空格分隔。

【输入样例】4
【输出样例】1 2 3 4
         12 13 14 5
         11 16 15 6
         10 9 8 7

public class Solution1 {
    
    
	/**
     * 目前已知最优雅的写法
     * Left-Right-Top-Down螺旋模板
     */	
    public int[][] CreateSpiral(int n) {
    
    
        int[][] res = new int[n][n];

        int L = 0;
        int R = n - 1;
        int T = 0;
        int D = n - 1;

        int index = 1;
        int remain = n * n;
        while (remain > 0) {
    
    
            for (int i = L; i <= R && remain > 0; i++) {
    
    
                res[T][i] = (index++);
                remain--;
            }
            T++;
            for (int i = T; i <= D && remain > 0; i++) {
    
    
                res[i][R] = (index++);
                remain--;
            }
            R--;
            for (int i = R; i >= L && remain > 0 ; i--) {
    
    
                res[D][i] = (index++);
                remain--;
            }
            D--;
            for (int i = D; i >= T && remain > 0; i--) {
    
    
                res[i][L] = (index++);
                remain--;
            }
            L++;
        }
        return res;
    }

    public static void main(String[] args) {
    
    
        Scanner sc = new Scanner(System.in);
        while (true) {
    
    
            int n = sc.nextInt();
            if (n == 0) {
    
    
                break;
            }
            int[][] res = new Solution1().CreateSpiral(n);
            for (int i = 0; i < n; i++) {
    
    
                for (int j = 0; j < n; j++) {
    
    
                    System.out.print(res[i][j] + " ");
                }
                System.out.println();
            }
        }
    }
}

2. 求解幸运数问题

【问题描述】小明同学学习了不同的进制之后,拿起了一些数字做起了游戏。小明同学知道,在日常生活中我们最常用的是十进制数,而在计算机中,二进制数也很常用。现在对于一个数字x,小明同学定义出了两个函数f(x)和g(x)。 f(x)表示把x这个数用十进制写出后各个数位上的数字之和。如f(123)=1+2+3=6。 g(x)表示把x这个数用二进制写出后各个数位上的数字之和。如123的二进制表示为1111011,那么,g(123)=1+1+1+1+0+1+1=6。 小明同学发现对于一些正整数x满足f(x)=g(x),他把这种数称为幸运数,现在他想知道,小于等于n的幸运数有多少个?

【输入描述】n(n≤100000)。
【输入描述】小于等于n的幸运数个数。
【输入样例】21
【输入样例】3

public class Solution2 {
    
    
	/**
     * 每一个数都判断是否是LuckyNumber即可,非常简单~
     */	
    public int getLuckyNumber(int n) {
    
    
        int cnt = 0;
        for (int i = 1; i <= n; i++) {
    
    
            cnt += (f(i) == g(i) ? 1 : 0);
        }
        return cnt;
    }

    private int f(int n) {
    
    
        if (n < 10) {
    
    
            return n;
        }
        return n % 10 + f(n / 10);
    }

    private int g(int n) {
    
    
        if (n < 2) {
    
    
            return n;
        }
        return  n & 1 + g(n >> 1);
        // 位运算永远的神
    }


    public static void main(String[] args) {
    
    
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        System.out.println(new Solution2().getLuckyNumber(n));
    }
}

3. 求解回文序列问题

【问题描述】如果一个数字序列逆置后跟原序列是一样的,则称这样的数字序列为回文序列。例如,{1,2,1}、{15,78,78,15}、{11,2,11}是回文序列,而{1,2,2}、{15,78,87,51}、{112,2,11}不是回文序列。现在给出一个数字序列,允许使用一种转换操作:选择任意两个相邻的数,然后从序列中移除这两个数,并将这两个数的和插入到这两个之前的位置(只插入一个和)。对于所给序列求出最少需要多少次操作可以将其变成回文序列。

【输入描述】:输入为两行,第1行为序列长度 n(1≤n≤50),第2行为序列中的n个整数item[i] (1≤item[i]≤1000),以空格分隔。
【输出描述】:输出一个数,表示最少需要的转换次数。

【输入样例】4
         1 1 1 3
【输出样例】2

public class Solution3 {
    
    
	/**
     * 每次计算最外面的一层,递归内层
     */
    public int trans2palindrome(int[] arr, int L, int R) {
    
    
        if (L >= R) {
    
    
            return 0;
        }
        int res = 0;
        int sumL = arr[L++];
        int sumR = arr[R--];
        while (L <= R) {
    
    
            if (sumL < sumR) {
    
    
                sumL += arr[L++];
                res++;
            } else if (sumL > sumR) {
    
    
                sumR += arr[R--];
                res++;
            } else {
    
    
                break;
            }
        }
        return res + trans2palindrome(arr, L, R);
    }

    public static void main(String[] args) {
    
    
        Scanner sc = new Scanner(System.in);
        int len = sc.nextInt();
        int[] arr = new int[len];
        for (int i = 0; i < len; i++) {
    
    
            arr[i] = sc.nextInt();
        }
        System.out.println(new Solution3().trans2palindrome(arr, 0, len -1));
    }
}

4. 求解投骰子游戏问题

【问题描述】玩家根据骰子的点数决定走的步数,即骰子点数为1时可以走一步,点数为2时可以走两步,点数为n时可以走n步。求玩家走到第n步(n≤骰子最大点数且投骰子的方法唯一)时总共有多少种投骰子的方法。

【输入描述】:输入包括一个整数n(1≤n≤6)。
【输出描述】:输出一个整数,表示投骰子的方法数。

【输入样例】:6
【输出样例】:32

public class Solution4 {
    
    
	/**
     * 回溯的最简单最初始版本———不需要记录路径,仅需要记录个数
     */
    public int ThrowDice(int n) {
    
    
        return traceBack(n);
    }

    private int traceBack(int remain) {
    
    
        if (remain == 0) {
    
    
            return 1;
        }
        int sum = 0;
        for (int i = 1; i <= 6 && i <= remain; i++) {
    
    
            sum += traceBack(remain - i);
        }
        return sum;
    }

    public static void main(String[] args) {
    
    
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        System.out.println(new Solution4().ThrowDice(n));
    }
}

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

⭐️ 这一定是全网最优美的Java解法 >_<

猜你喜欢

转载自blog.csdn.net/m0_46202073/article/details/114996082