leetcode526. 优美的排列(回溯算法-java)

文章介绍了LeetCode第526题《优美排列》的解题思路,主要涉及动态规划和回溯算法。对于给定的整数n,优美排列是指数组perm(1-indexed)满足perm[i]能被i整除或者i能被perm[i]整除的排列方式。文章提供了使用回溯法的Java代码示例,通过预处理每个位置可放置的数字并进行递归搜索来找到所有可能的优美排列。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

leetcode526. 优美的排列

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/beautiful-arrangement

题目描述

假设有从 1 到 n 的 n 个整数。用这些整数构造一个数组 perm(下标从 1 开始),只要满足下述条件 之一 ,该数组就是一个 优美的排列 :

perm[i] 能够被 i 整除
i 能够被 perm[i] 整除
给你一个整数 n ,返回可以构造的 优美排列 的 数量 。

示例 1:
输入:n = 2
输出:2
解释:
第 1 个优美的排列是 [1,2]:
- perm[1] = 1 能被 i = 1 整除
- perm[2] = 2 能被 i = 2 整除
第 2 个优美的排列是 [2,1]:
- perm[1] = 2 能被 i = 1 整除
- i = 2 能被 perm[2] = 1 整除

示例 2:
输入:n = 1
输出:1

提示:
1 <= n <= 15

接替思路

我们先求出每个位置上能放置那些数字,每个位置能放的数字,用一个数组保存起来:
我们以4 为例:
1.位置可以放1,2,3,4
2.位置可以放,1,2,4
3.位置可以放1,3
4,位置可以放1,4
四个位置排列组合,
在这里插入图片描述
每个位置上的数字不能重复,我们要排列组合这四个位置上的数字,并且去重,就可以用回溯算法解答了.
回溯过程中,我们可以用 visvis 数组标记哪些数被使用过,每次我们选中一个数 x,我们就将 flag[x] 标记为 true,回溯完成后,我们再将其置为 falsefalse。

特别地,为了优化回溯效率,我们可以预处理每个位置的符合条件的数有哪些,用二维数组 ans 保存。当我们尝试向位置 index放入数时,我们只需要遍历 ans[index] 即可。

回溯算法的框架:
result = []
def process(选择列表):
if 满足结束条件:
result.add(路径)
return
for 选择 in 选择列表:
做选择
backtrack(路径, 选择列表)
撤销选择

代码演示:

package test.day100;

import test.day12.Demo02_IsBST;

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

/**
 * 优美的排列
 */
public class Test31 {

    List<Integer>[] ans ;
    boolean[]flag;
    int num;

    /**
     * 优美的排列
     * @param n
     * @return
     */
    public int countArrangement(int n) {
        ans = new List[n + 1];
        flag = new boolean[n + 1];
        ans[0] = new ArrayList<Integer>();
        //每个位置能放置哪些数字,提前初始化出来.
        for (int i = 1; i <= n;i++){
            ans[i] = new ArrayList<>();
            for (int j = 1;j <= n;j++){
                if (i % j == 0 || j % i == 0){
                    ans[i].add(j);
                }
            }
        }
        process(n,1);
        return num;
    }

    /**
     * 回溯算法
     * @param n
     * @param index
     */
    public void process(int n,int index){
        //选完n个数满足  返回
        if (index == n + 1){
            num++;
            return;
        }
        //选择列表
        for (int x : ans[index]){
            //去重,没选过的数字才可以选择
            if (!flag[x]){
                //选择
                flag[x] = true;
                process(n,index + 1);
                //撤销选择
                flag[x] = false;
            }
        }
    }


}

动态规划专题

leetcode464. 我能赢吗

leetcode97. 交错字符串

leetcode474. 一和零

leetcode583. 两个字符串的删除操作

leetcode514. 自由之路

leetcode887. 鸡蛋掉落

leetcode72. 编辑距离

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值