Skip to content

Commit 384135c

Browse files
authored
Improved tasks 1659, 3435
1 parent 8000760 commit 384135c

File tree

3 files changed

+174
-139
lines changed
  • src
    • main/kotlin
      • g1601_1700/s1659_maximize_grid_happiness
      • g3401_3500/s3435_frequencies_of_shortest_supersequences
    • test/kotlin/g3401_3500/s3435_frequencies_of_shortest_supersequences

3 files changed

+174
-139
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,80 +1,112 @@
11
package g1601_1700.s1659_maximize_grid_happiness
22

33
// #Hard #Dynamic_Programming #Bit_Manipulation #Bitmask #Memoization
4-
// #2023_06_15_Time_181_ms_(100.00%)_Space_36.9_MB_(100.00%)
4+
// #2025_04_04_Time_44_ms_(100.00%)_Space_56.67_MB_(100.00%)
55

6-
class Solution {
7-
private var m = 0
8-
private var n = 0
9-
private lateinit var dp: Array<Array<Array<Array<IntArray>>>>
10-
private val notPlace = 0
11-
private val intro = 1
12-
private val extro = 2
13-
private var mod = 0
6+
import kotlin.math.max
147

15-
fun getMaxGridHappiness(m: Int, n: Int, introvertsCount: Int, extrovertsCount: Int): Int {
16-
this.m = m
17-
this.n = n
18-
val numOfState = Math.pow(3.0, n.toDouble()).toInt()
19-
dp = Array(m) {
20-
Array(n) {
21-
Array(introvertsCount + 1) {
22-
Array(extrovertsCount + 1) { IntArray(numOfState) }
23-
}
24-
}
8+
@Suppress("kotlin:S107")
9+
class Solution {
10+
private fun maxHappiness(
11+
index: Int,
12+
m: Int,
13+
n: Int,
14+
introverts: Int,
15+
extroverts: Int,
16+
board: Int,
17+
dp: Array<Array<Array<IntArray>>>,
18+
tmask: Int,
19+
): Int {
20+
if (index >= m * n) {
21+
return 0
22+
}
23+
if (dp[index][introverts][extroverts][board] != 0) {
24+
return dp[index][introverts][extroverts][board]
25+
}
26+
var introScore = -1
27+
var extroScore = -1
28+
if (introverts > 0) {
29+
val newBoard = ((board shl 2) or INTROVERT) and tmask
30+
introScore =
31+
(
32+
120 +
33+
adjust(board, INTROVERT, n, index) +
34+
maxHappiness(
35+
index + 1,
36+
m,
37+
n,
38+
introverts - 1,
39+
extroverts,
40+
newBoard,
41+
dp,
42+
tmask,
43+
)
44+
)
45+
}
46+
if (extroverts > 0) {
47+
val newBoard = ((board shl 2) or EXTROVERT) and tmask
48+
extroScore =
49+
(
50+
40 +
51+
adjust(board, EXTROVERT, n, index) +
52+
maxHappiness(
53+
index + 1,
54+
m,
55+
n,
56+
introverts,
57+
extroverts - 1,
58+
newBoard,
59+
dp,
60+
tmask,
61+
)
62+
)
2563
}
26-
mod = numOfState / 3
27-
return dfs(0, 0, introvertsCount, extrovertsCount, 0)
64+
val newBoard = ((board shl 2) or NONE) and tmask
65+
val skip = maxHappiness(index + 1, m, n, introverts, extroverts, newBoard, dp, tmask)
66+
dp[index][introverts][extroverts][board] =
67+
max(skip, max(introScore, extroScore))
68+
return dp[index][introverts][extroverts][board]
2869
}
2970

30-
private fun dfs(x: Int, y: Int, ic: Int, ec: Int, state: Int): Int {
31-
if (x == m) {
32-
return 0
33-
} else if (y == n) {
34-
return dfs(x + 1, 0, ic, ec, state)
35-
}
36-
if (dp[x][y][ic][ec][state] != 0) {
37-
return dp[x][y][ic][ec][state]
71+
private fun adjust(board: Int, thisIs: Int, col: Int, index: Int): Int {
72+
val shiftBy = 2 * (col - 1)
73+
var left = board and 0x03
74+
if (index % col == 0) {
75+
left = NONE
3876
}
39-
// 1 - not place
40-
var max = dfs(x, y + 1, ic, ec, state % mod * 3)
41-
val up = state / mod
42-
val left = state % 3
43-
// 2 - place intro
44-
if (ic > 0) {
45-
var temp = 120
46-
if (x > 0 && up != notPlace) {
47-
temp -= 30
48-
temp += if (up == intro) -30 else 20
77+
val up = (board shr shiftBy) and 0x03
78+
val combination = intArrayOf(left, up)
79+
var adjustment = 0
80+
for (neighbor in combination) {
81+
if (neighbor == NONE) {
82+
continue
4983
}
50-
if (y > 0 && left != notPlace) {
51-
temp -= 30
52-
temp += if (left == intro) -30 else 20
84+
if (neighbor == INTROVERT && thisIs == INTROVERT) {
85+
adjustment -= 60
86+
} else if (neighbor == INTROVERT && thisIs == EXTROVERT) {
87+
adjustment -= 10
88+
} else if (neighbor == EXTROVERT && thisIs == INTROVERT) {
89+
adjustment -= 10
90+
} else if (neighbor == EXTROVERT && thisIs == EXTROVERT) {
91+
adjustment += 40
5392
}
54-
var nextState = state
55-
nextState %= mod
56-
nextState *= 3
57-
nextState += intro
58-
max = Math.max(max, temp + dfs(x, y + 1, ic - 1, ec, nextState))
5993
}
60-
// 3 - place extro
61-
if (ec > 0) {
62-
var temp = 40
63-
if (x > 0 && up != notPlace) {
64-
temp += 20
65-
temp += if (up == intro) -30 else 20
66-
}
67-
if (y > 0 && left != notPlace) {
68-
temp += 20
69-
temp += if (left == intro) -30 else 20
94+
return adjustment
95+
}
96+
97+
fun getMaxGridHappiness(m: Int, n: Int, introvertsCount: Int, extrovertsCount: Int): Int {
98+
val dp = Array<Array<Array<IntArray>>>(m * n) {
99+
Array<Array<IntArray>>(introvertsCount + 1) {
100+
Array<IntArray>(extrovertsCount + 1) { IntArray((1 shl (2 * n))) }
70101
}
71-
var nextState = state
72-
nextState %= mod
73-
nextState *= 3
74-
nextState += extro
75-
max = Math.max(max, temp + dfs(x, y + 1, ic, ec - 1, nextState))
76102
}
77-
dp[x][y][ic][ec][state] = max
78-
return max
103+
val tmask = (1 shl (2 * n)) - 1
104+
return maxHappiness(0, m, n, introvertsCount, extrovertsCount, 0, dp, tmask)
105+
}
106+
107+
companion object {
108+
private const val NONE = 0
109+
private const val INTROVERT = 1
110+
private const val EXTROVERT = 2
79111
}
80112
}
Original file line numberDiff line numberDiff line change
@@ -1,103 +1,106 @@
11
package g3401_3500.s3435_frequencies_of_shortest_supersequences
22

33
// #Hard #Array #String #Bit_Manipulation #Graph #Enumeration #Topological_Sort
4-
// #2025_01_29_Time_35_ms_(100.00%)_Space_43.62_MB_(100.00%)
4+
// #2025_04_04_Time_275_ms_(100.00%)_Space_49.81_MB_(100.00%)
55

66
class Solution {
7-
private var m = 0
8-
private var forcedMask = 0
9-
private lateinit var adj: IntArray
10-
private val idxToChar = CharArray(26)
11-
private val charToIdx = IntArray(26)
12-
private val used = BooleanArray(26)
7+
private var min = Int.Companion.MAX_VALUE
8+
private var lists: MutableList<IntArray> = ArrayList<IntArray>()
139

1410
fun supersequences(words: Array<String>): List<List<Int>> {
15-
charToIdx.fill(-1)
16-
for (w in words) {
17-
used[w[0].code - 'a'.code] = true
18-
used[w[1].code - 'a'.code] = true
11+
val pairs = Array<BooleanArray>(26) { BooleanArray(26) }
12+
val counts = IntArray(26)
13+
for (word in words) {
14+
val a = word[0].code - 'a'.code
15+
val b = word[1].code - 'a'.code
16+
if (!pairs[a][b]) {
17+
pairs[a][b] = true
18+
counts[a]++
19+
counts[b]++
20+
}
1921
}
20-
// Map each used letter to an index [0..m-1]
21-
for (c in 0..25) {
22-
if (used[c]) {
23-
idxToChar[m] = (c + 'a'.code).toChar()
24-
charToIdx[c] = m++
22+
val links: Array<ArrayList<Int>> = Array<ArrayList<Int>>(26) { ArrayList<Int>() }
23+
val counts1 = IntArray(26)
24+
val sides = IntArray(26)
25+
for (i in 0..25) {
26+
for (j in 0..25) {
27+
if (pairs[i][j]) {
28+
links[i].add(j)
29+
counts1[j]++
30+
sides[i] = sides[i] or 1
31+
sides[j] = sides[j] or 2
32+
}
2533
}
2634
}
27-
adj = IntArray(m)
28-
// Build graph and record forced duplicates
29-
for (w in words) {
30-
val u = charToIdx[w[0].code - 'a'.code]
31-
val v = charToIdx[w[1].code - 'a'.code]
32-
if (u == v) {
33-
forcedMask = forcedMask or (1 shl u)
35+
val arr = IntArray(26)
36+
for (i in 0..25) {
37+
if (counts[i] <= 1) {
38+
arr[i] = counts[i]
39+
} else if (counts1[i] == 0 || sides[i] != 3) {
40+
arr[i] = 1
41+
} else if (pairs[i][i]) {
42+
arr[i] = 2
3443
} else {
35-
adj[u] = adj[u] or (1 shl v)
44+
arr[i] = -1
3645
}
3746
}
38-
// Try all supersets of forcedMask; keep those that kill all cycles
39-
var best = 9999
40-
val goodSets: MutableList<Int> = ArrayList<Int>()
41-
for (s in 0..<(1 shl m)) {
42-
if ((s and forcedMask) != forcedMask) {
43-
continue
44-
}
45-
val size = Integer.bitCount(s)
46-
if (size <= best && !hasCycle(s)) {
47-
if (size < best) {
48-
best = size
49-
goodSets.clear()
50-
}
51-
goodSets.add(s)
47+
dfs(links, 0, arr, IntArray(26), 0)
48+
val res: MutableList<MutableList<Int>> = ArrayList<MutableList<Int>>()
49+
for (arr1 in lists) {
50+
val list: MutableList<Int> = ArrayList<Int>()
51+
for (n in arr1) {
52+
list.add(n)
5253
}
54+
res.add(list)
55+
}
56+
return res
57+
}
58+
59+
private fun dfs(links: Array<ArrayList<Int>>, i: Int, arr1: IntArray, arr: IntArray, n: Int) {
60+
if (n > min) {
61+
return
5362
}
54-
// Build distinct freq arrays from these sets
55-
val seen: MutableSet<String> = HashSet<String>()
56-
val ans: MutableList<MutableList<Int>> = ArrayList<MutableList<Int>>()
57-
for (s in goodSets) {
58-
val freq = IntArray(26)
59-
for (i in 0..<m) {
60-
freq[idxToChar[i].code - 'a'.code] = if ((s and (1 shl i)) != 0) 2 else 1
63+
if (i == 26) {
64+
if (!chk(links, arr)) {
65+
return
6166
}
62-
val key = freq.contentToString()
63-
if (seen.add(key)) {
64-
val tmp: MutableList<Int> = ArrayList<Int>()
65-
for (f in freq) {
66-
tmp.add(f)
67-
}
68-
ans.add(tmp)
67+
if (n < min) {
68+
min = n
69+
lists = ArrayList<IntArray>()
70+
lists.add(arr.clone())
71+
} else if (n == min) {
72+
lists.add(arr.clone())
6973
}
74+
return
75+
}
76+
if (arr1[i] >= 0) {
77+
arr[i] = arr1[i]
78+
dfs(links, i + 1, arr1, arr, n + arr1[i])
79+
} else {
80+
arr[i] = 1
81+
dfs(links, i + 1, arr1, arr, n + 1)
82+
arr[i] = 2
83+
dfs(links, i + 1, arr1, arr, n + 2)
7084
}
71-
return ans
7285
}
7386

74-
private fun hasCycle(mask: Int): Boolean {
75-
val color = IntArray(m)
76-
for (i in 0..<m) {
77-
if (((mask shr i) and 1) == 0 && color[i] == 0 && dfs(i, color, mask)) {
78-
return true
87+
private fun chk(links: Array<ArrayList<Int>>, arr: IntArray): Boolean {
88+
for (i in 0..25) {
89+
if (arr[i] == 1 && dfs1(links, arr, BooleanArray(26), i)) {
90+
return false
7991
}
8092
}
81-
return false
93+
return true
8294
}
8395

84-
private fun dfs(u: Int, color: IntArray, mask: Int): Boolean {
85-
color[u] = 1
86-
var nxt = adj[u]
87-
while (nxt != 0) {
88-
val v = Integer.numberOfTrailingZeros(nxt)
89-
nxt = nxt and (nxt - 1)
90-
if (((mask shr v) and 1) == 1) {
91-
continue
92-
}
93-
if (color[v] == 1) {
94-
return true
95-
}
96-
if (color[v] == 0 && dfs(v, color, mask)) {
96+
private fun dfs1(links: Array<ArrayList<Int>>, arr: IntArray, seens: BooleanArray, i: Int): Boolean {
97+
seens[i] = true
98+
for (next in links[i]) {
99+
if (arr[next] == 1 && (seens[next] || dfs1(links, arr, seens, next))) {
97100
return true
98101
}
99102
}
100-
color[u] = 2
103+
seens[i] = false
101104
return false
102105
}
103106
}

src/test/kotlin/g3401_3500/s3435_frequencies_of_shortest_supersequences/SolutionTest.kt

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,11 @@ internal class SolutionTest {
1212
equalTo(
1313
listOf(
1414
listOf(
15-
2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
15+
1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1616
0, 0, 0, 0, 0, 0,
1717
),
1818
listOf(
19-
1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
19+
2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2020
0, 0, 0, 0, 0, 0,
2121
),
2222
),

0 commit comments

Comments
 (0)