题目
题目链接
解题思路
- 题目要求通过一次交换操作得到字典序最小的排列
- 解题策略:
- 如果存在位置 \(i\) 使得 \(a[i] \neq i\),则找到这样的最小位置 \(i\)
- 将 \(a[i]\) 与 \(b[i]\)(即值 \(i\) 所在的位置)进行交换
- 如果所有位置都满足 \(a[i]=i\),则交换最后两个位置
- 使用辅助数组 \(b\) 记录每个数字的位置,方便查找
代码
#include <iostream>
#include <vector>
using namespace std;int main() {int n;cin >> n;vector<int> a(n + 1);vector<int> pos(n + 1); // 记录每个数字的位置// 读入数组并记录位置for(int i = 1; i <= n; i++) {cin >> a[i];pos[a[i]] = i;}// 寻找第一个不在正确位置的数for(int i = 1; i <= n; i++) {if(a[i] != i) {// 交换a[i]和值i所在位置的数int j = pos[i];swap(a[i], a[j]);// 输出结果for(int k = 1; k <= n; k++) {cout << a[k] << (k == n ? '\n' : ' ');}return 0;}}// 如果所有数都在正确位置,交换最后两个数swap(a[n], a[n-1]);for(int i = 1; i <= n; i++) {cout << a[i] << (i == n ? '\n' : ' ');}return 0;
}
import java.util.*;public class Main {public static void main(String[] args) {Scanner sc = new Scanner(System.in);int n = sc.nextInt();int[] a = new int[n + 1];int[] pos = new int[n + 1]; // 记录每个数字的位置// 读入数组并记录位置for(int i = 1; i <= n; i++) {a[i] = sc.nextInt();pos[a[i]] = i;}// 寻找第一个不在正确位置的数for(int i = 1; i <= n; i++) {if(a[i] != i) {// 交换a[i]和值i所在位置的数int j = pos[i];int temp = a[i];a[i] = a[j];a[j] = temp;// 输出结果for(int k = 1; k <= n; k++) {System.out.print(a[k] + (k == n ? "\n" : " "));}return;}}// 如果所有数都在正确位置,交换最后两个数int temp = a[n];a[n] = a[n-1];a[n-1] = temp;for(int i = 1; i <= n; i++) {System.out.print(a[i] + (i == n ? "\n" : " "));}}
}
n = int(input())
a = [0] + list(map(int, input().split()))
pos = [0] * (n + 1) # 记录每个数字的位置# 记录每个数字的位置
for i in range(1, n + 1):pos[a[i]] = i# 寻找第一个不在正确位置的数
for i in range(1, n + 1):if a[i] != i:# 交换a[i]和值i所在位置的数j = pos[i]a[i], a[j] = a[j], a[i]# 输出结果print(*a[1:])exit()# 如果所有数都在正确位置,交换最后两个数
a[n], a[n-1] = a[n-1], a[n]
print(*a[1:])
算法及复杂度
- 算法:贪心
- 时间复杂度:\(\mathcal{O}(n)\) - 只需要遍历一次数组
- 空间复杂度:\(\mathcal{O}(n)\) - 需要额外的数组记录位置信息