Acwing 4204. 构造矩阵
请你构造一个 n×n 的整数矩阵。
要求,矩阵满足下列所有条件:
- 矩阵中的所有元素的取值范围为 [0,n−1]。
- 矩阵主对角线上的所有元素都为 0。主对角线是指从左上角到右下角这一斜线方向的对角线。
- 该矩阵是对称矩阵。对称矩阵是指以主对角线为对称轴,各元素对应相等的矩阵。
- 同一行上的所有元素两两不同。
- 同一列上的所有元素两两不同。
输入格式
一个整数 n。
输出格式
共 n 行,每行 n个空格隔开的整数,表示整个矩阵。
如果方案不唯一,输出任意合理方案均可。
数据范围
前三个测试点满足 2≤n≤10。
所有测试点满足 2≤n≤1000,n 保证是偶数。
输入样例1:
2
输出样例1:
0 1 1 0
输入样例2:
4
输出样例2:
0 1 3 2
1 0 2 3
3 2 0 1
2 3 1 0
思路:
考虑n - 1行列如何构造,例如n = 4
构造3行3列得
1 2 3
2 3 1
3 1 2
将对角线元素添加到行尾和列为,并替换对角线元素为0,得
0 2 3 1
2 0 1 3
3 1 0 2
1 3 2 0
满足要求
import java.util.*;
import java.io.*;
public class Main {
public static void main(String[] sss) throws IOException{
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[][] res = new int[n][n];
for (int i = 0; i < n - 1; i++) {
for (int j = 0; j < n - 1; j++) {
res[i][j] = (i + j) % (n - 1) + 1;
}
}
for (int i = 0; i < n - 1; i++) {
res[i][n - 1] = res[n - 1][i] = res[i][i];
res[i][i] = 0;
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++)
bw.write(res[i][j] + " ");
bw.write("\n");
}
bw.close();
// br.close();
}
}
767. 重构字符串
给定一个字符串 s ,检查是否能重新排布其中的字母,使得两相邻的字符不同。
返回 s 的任意可能的重新排列。若不可行,返回空字符串 “” 。
示例 1:
输入: s = “aab” 输出: “aba”
示例 2:
输入: s = “aaab” 输出: “”
提示:
- 1 <= s.length <= 500
- s 只包含小写字母
思路:
构造,按字符出现次数从大到小排序,若存在cnt(c) > (n + 1) / 2
,说明无解
否则,插空放即可
class Solution {
public String reorganizeString(String s) {
int n = s.length();
int[][] cnt = new int[26][2];
for (int i = 0; i < s.length(); i++) {
cnt[s.charAt(i) - 'a'][0]++;
}
for (int i = 0; i < 26; i++)
cnt[i][1] = i;
Arrays.sort(cnt, (o1, o2) -> (o2[0] - o1[0]));
if (cnt[0][0] > (n + 1) / 2)
return "";
char[] res = new char[n];
Arrays.fill(res, '0');
int idx = 0;
for (int i = 0; i < 2; i++) {
int j = i;
while (j < n && cnt[idx][0] > 0) {
res[j] = (char)(cnt[idx][1] + 'a');
j += 2;
cnt[idx][0]--;
if (cnt[idx][0] == 0)
idx++;
}
}
return new String(res);
}
}
358. K 距离间隔重排字符串
给你一个非空的字符串 s 和一个整数 k ,你要将这个字符串 s 中的字母进行重新排列,使得重排后的字符串中相同字母的位置间隔距离 至少 为 k 。如果无法做到,请返回一个空字符串 “”。
示例 1:
输入: s = “aabbcc”, k = 3 输出: “abcabc” 解释: 相同的字母在新的字符串中间隔至少 3 个单位距离。
示例 2:
输入: s = “aaabc”, k = 3 输出: “” 解释: 没有办法找到可能的重排结果。
示例 3:
输入: s = “aaadbbcc”, k = 2 输出: “abacabcd” 解释: 相同的字母在新的字符串中间隔至少 2 个单位距离。
提示:
- 1 <= s.length <= 3 * 105
- s 仅由小写英文字母组成
- 0 <= k <= s.length
思路:
相较于767,k = 2 -> k不定
优先队列 + 队列
class Solution {
public String rearrangeString(String s, int k) {
if (k <= 1)
return s;
if (k > 26)
return "";
int[][] cnt = new int[26][2];
for (int i = 0; i < 26; i++)
cnt[i][1] = i;
int n = s.length();
for (int i = 0; i < n; i++) {
cnt[s.charAt(i) - 'a'][0] ++ ;
}
PriorityQueue<int[]> q = new PriorityQueue<>((o1, o2) -> (o2[0] == o1[0] ? o1[1] - o2[1] : o2[0] - o1[0]));
for (int i = 0; i < 26; i++)
if (cnt[i][0] != 0)
q.offer(cnt[i]);
Queue<int[]> q2 = new LinkedList<>();
int sum = n;
StringBuilder sb = new StringBuilder();
while (!q.isEmpty()) {
int size = q.size();
if (size < Math.min(k, sum))
return "";
int c = Math.min(k, sum);
sum -= c;
while (c-- > 0) {
q2.offer(q.poll());
}
while (!q2.isEmpty()) {
int[] u = q2.poll();
sb.append((char)(u[1] + 'a'));
u[0]--;
if (u[0] > 0)
q.offer(u);
}
}
return sb.toString();
}
}
// API
class Solution {
public String rearrangeString(String s, int k) {
if(k <= 1)
return s;
Map<Character, Integer> map = new HashMap<>();
int n = s.length();
for (int i = 0; i < n; i++)
map.merge(s.charAt(i), 1, Integer::sum);
PriorityQueue<Map.Entry<Character, Integer>> maxHeap = new PriorityQueue<>((o1, o2) -> (o2.getValue() - o1.getValue()));
maxHeap.addAll(map.entrySet());
Queue<Map.Entry<Character, Integer>> q = new LinkedList<>();
StringBuilder sb = new StringBuilder();
while (!maxHeap.isEmpty()) {
var cur = maxHeap.poll();
sb.append(cur.getKey());
cur.setValue(cur.getValue() - 1);
q.offer(cur);
if (q.size() == k) {
cur = q.poll();
if (cur.getValue() > 0)
maxHeap.offer(cur);
}
}
return sb.length() == n ? sb.toString() : "";
}
}