小Q的非素数和排列问题 | 豆包MarsCode AI刷题

87 阅读3分钟

题目

小C对排列很感兴趣,她想知道有多少个长度为n的排列满足任意两个相邻元素之和都不是素数。排列定义为一个长度为n的数组,其中包含从1到n的所有整数,每个数字恰好出现一次。

题目理解

  1. 排列的定义

    • 排列是一个长度为 n 的数组,其中包含从 1 到 n 的所有整数,每个数字恰好出现一次。
    • 例如,当 n = 3 时,可能的排列有 [1, 2, 3][1, 3, 2][2, 1, 3][2, 3, 1][3, 1, 2][3, 2, 1]
  2. 相邻元素之和

    • 对于一个排列,任意两个相邻元素之和不能是素数。
    • 例如,在排列 [1, 2, 3] 中,相邻元素之和为 1 + 2 = 3 和 2 + 3 = 5,其中 3 和 5 都是素数,因此这个排列不符合条件。
  3. 目标

    • 需要计算出所有满足条件的排列的数量。

解题思路

  1. 生成所有排列

    • 首先,生成从 1 到 n 的所有排列。可以使用递归或迭代的方式来生成所有排列。
  2. 检查相邻元素之和

    • 对于每一个生成的排列,检查相邻元素之和是否为素数。如果某个排列中所有相邻元素之和都不是素数,则该排列符合条件。
  3. 计数符合条件的排列

    • 统计所有符合条件的排列的数量,并返回结果。

数据结构与算法选择

  1. 数据结构

    • 使用 List<List<Integer>> 来存储所有生成的排列。
    • 使用 List<Integer> 来存储单个排列。
  2. 算法

    • 排列生成:使用递归或迭代的方式生成所有排列。
    • 素数检查:编写一个函数 isPrime 来判断一个数是否为素数。
    • 条件检查:遍历每个排列,检查相邻元素之和是否为素数。

代码思路

  1. 生成所有排列:通过递归函数 result 生成从 1 到 n 的所有排列,并将这些排列存储在 List<List<Integer>> list 中。
  2. 检查相邻元素之和是否为素数:遍历每一个排列,检查相邻元素之和是否为素数。如果某个排列中所有相邻元素之和都不是素数,则计数器 count 加一。
  3. 返回结果:最终返回满足条件的排列数量。

代码

import java.util.ArrayList;
import java.util.List;

public class Main {
    public static int solution(int n) {
        // 排列的基础上更近一步加一点东西
        List<List<Integer>> list = new ArrayList<>();
        int [] nums = new int[n];
        for(int i = 0; i < n; i++){
            nums[i] = i + 1;
        }

        result(nums, 0,list);

        //进行判断
        int count = 0;
        for(List<Integer> set : list){
            int flag = 0;
            for(int i = 0; i < set.size() - 1; i++){
                if( isPrime( set.get(i) + set.get(i + 1)) ){
                    flag = 1;
                    break;
                }
            }

            if(flag == 0) count ++;
        }
        return count;
    }

    //首先建立一个递归函数求解所有的情况
    public static void result(int nums[], int start, List<List<Integer>>list){
        //首先设置出口

        if(start == nums.length - 1){
            List<Integer> subsets = new ArrayList<>();
            for(int target : nums){
                subsets.add(target);
            }
            list.add(new ArrayList<>(subsets));
        }

        // 进行递归求解
        for(int i = start; i < nums.length; i++){
            // 进行交换
            int temp = nums[i];
            nums[i] = nums[start];
            nums[start] = temp;

            //进行递归
            result(nums, start + 1, list);

            //进行回溯,交换回原来的样子
            temp = nums[i];
            nums[i] = nums[start];
            nums[start] = temp;
        }
    }

    public static boolean isPrime(int n){
        if(n <= 1) return false;
        if(n == 2) return true;
        for(int i = 2; i <= Math.sqrt(n); i++){
            if(n % i == 0) return false;
        }
        return true;
    }

    public static void main(String[] args) {
        System.out.println(solution(5) == 4);
        System.out.println(solution(3) == 0);
        System.out.println(solution(6) == 24);
    }
}

代码分析

  1. 生成排列

    • 你使用了递归的方式来生成所有排列。通过交换数组中的元素来生成不同的排列,并在递归结束后进行回溯,恢复数组的状态。
    • 这种方法是经典的排列生成方法,适用于较小的 n 值。
  2. 检查素数

    • 你使用了 isPrime 函数来判断一个数是否为素数。这个函数的实现是正确的,通过从 2 到 sqrt(n) 的范围内检查是否有因子来判断素数。
  3. 主函数

    • 在 main 函数中,你测试了几个样例,确保代码的正确性。