Off-by-one on range boundaries
Wrong move: Loop endpoints miss first/last candidate.
Usually fails on: Fails on minimal arrays and exact-boundary answers.
Fix: Re-derive loops from inclusive/exclusive ranges before coding.
Move from brute-force thinking to an efficient approach using array strategy.
You are given an array nums of positive integers and a positive integer k.
A subset of nums is beautiful if it does not contain two integers with an absolute difference equal to k.
Return the number of non-empty beautiful subsets of the array nums.
A subset of nums is an array that can be obtained by deleting some (possibly none) elements from nums. Two subsets are different if and only if the chosen indices to delete are different.
Example 1:
Input: nums = [2,4,6], k = 2 Output: 4 Explanation: The beautiful subsets of the array nums are: [2], [4], [6], [2, 6]. It can be proved that there are only 4 beautiful subsets in the array [2,4,6].
Example 2:
Input: nums = [1], k = 1 Output: 1 Explanation: The beautiful subset of the array nums is [1]. It can be proved that there is only 1 beautiful subset in the array [1].
Constraints:
1 <= nums.length <= 181 <= nums[i], k <= 1000Problem summary: You are given an array nums of positive integers and a positive integer k. A subset of nums is beautiful if it does not contain two integers with an absolute difference equal to k. Return the number of non-empty beautiful subsets of the array nums. A subset of nums is an array that can be obtained by deleting some (possibly none) elements from nums. Two subsets are different if and only if the chosen indices to delete are different.
Start with the most direct exhaustive search. That gives a correctness anchor before optimizing.
Pattern signal: Array · Hash Map · Math · Dynamic Programming · Backtracking
[2,4,6] 2
[1] 1
construct-the-lexicographically-largest-valid-sequence)Source-backed implementations are provided below for direct study and interview prep.
// Accepted solution for LeetCode #2597: The Number of Beautiful Subsets
class Solution {
private int[] nums;
private int[] cnt = new int[1010];
private int ans = -1;
private int k;
public int beautifulSubsets(int[] nums, int k) {
this.k = k;
this.nums = nums;
dfs(0);
return ans;
}
private void dfs(int i) {
if (i >= nums.length) {
++ans;
return;
}
dfs(i + 1);
boolean ok1 = nums[i] + k >= cnt.length || cnt[nums[i] + k] == 0;
boolean ok2 = nums[i] - k < 0 || cnt[nums[i] - k] == 0;
if (ok1 && ok2) {
++cnt[nums[i]];
dfs(i + 1);
--cnt[nums[i]];
}
}
}
// Accepted solution for LeetCode #2597: The Number of Beautiful Subsets
func beautifulSubsets(nums []int, k int) int {
ans := -1
n := len(nums)
cnt := [1010]int{}
var dfs func(int)
dfs = func(i int) {
if i >= n {
ans++
return
}
dfs(i + 1)
ok1 := nums[i]+k >= len(cnt) || cnt[nums[i]+k] == 0
ok2 := nums[i]-k < 0 || cnt[nums[i]-k] == 0
if ok1 && ok2 {
cnt[nums[i]]++
dfs(i + 1)
cnt[nums[i]]--
}
}
dfs(0)
return ans
}
# Accepted solution for LeetCode #2597: The Number of Beautiful Subsets
class Solution:
def beautifulSubsets(self, nums: List[int], k: int) -> int:
def dfs(i: int) -> None:
nonlocal ans
if i >= len(nums):
ans += 1
return
dfs(i + 1)
if cnt[nums[i] + k] == 0 and cnt[nums[i] - k] == 0:
cnt[nums[i]] += 1
dfs(i + 1)
cnt[nums[i]] -= 1
ans = -1
cnt = Counter()
dfs(0)
return ans
// Accepted solution for LeetCode #2597: The Number of Beautiful Subsets
/**
* [2597] The Number of Beautiful Subsets
*/
pub struct Solution {}
// submission codes start here
use std::collections::{BTreeMap, HashMap};
impl Solution {
pub fn beautiful_subsets(nums: Vec<i32>, k: i32) -> i32 {
let mut map = HashMap::new();
for i in nums {
let value = i % k;
let entry = map.entry(value).or_insert(BTreeMap::new());
let group_entry = entry.entry(i).or_insert(0);
*group_entry += 1;
}
let mut result = 1;
for group in map.values() {
let n = group.len();
// (x, y) x表示不选择第i个数
// y表示选择第i个数
let mut dp = vec![(0, 0); n];
// 懒得用迭代器移来移去
// 直接复制到数组开干
let array: Vec<(i32, i32)> = group.iter().map(|(x, y)| (*x, *y)).collect();
for (i, &(key, count)) in array.iter().enumerate() {
if i == 0 {
dp[0].0 = 1;
dp[0].1 = (1 << count) - 1;
} else {
dp[i].0 = dp[i - 1].0 + dp[i - 1].1;
if key - array[i - 1].0 == k {
dp[i].1 = dp[i - 1].0 * ((1 << count) - 1);
} else {
dp[i].1 = (dp[i - 1].0 + dp[i - 1].1) * ((1 << count) - 1);
}
}
}
result *= dp[n - 1].0 + dp[n - 1].1;
}
result - 1
}
}
// submission codes end
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_2597() {
assert_eq!(4, Solution::beautiful_subsets(vec![2, 4, 6], 2));
assert_eq!(1, Solution::beautiful_subsets(vec![1], 1));
}
}
// Accepted solution for LeetCode #2597: The Number of Beautiful Subsets
function beautifulSubsets(nums: number[], k: number): number {
let ans: number = -1;
const cnt: number[] = new Array(1010).fill(0);
const n: number = nums.length;
const dfs = (i: number) => {
if (i >= n) {
++ans;
return;
}
dfs(i + 1);
const ok1: boolean = nums[i] + k >= 1010 || cnt[nums[i] + k] === 0;
const ok2: boolean = nums[i] - k < 0 || cnt[nums[i] - k] === 0;
if (ok1 && ok2) {
++cnt[nums[i]];
dfs(i + 1);
--cnt[nums[i]];
}
};
dfs(0);
return ans;
}
Use this to step through a reusable interview workflow for this problem.
Pure recursion explores every possible choice at each step. With two choices per state (take or skip), the decision tree has 2ⁿ leaves. The recursion stack uses O(n) space. Many subproblems are recomputed exponentially many times.
Each cell in the DP table is computed exactly once from previously solved subproblems. The table dimensions determine both time and space. Look for the state variables — each unique combination of state values is one cell. Often a rolling array can reduce space by one dimension.
Review these before coding to avoid predictable interview regressions.
Wrong move: Loop endpoints miss first/last candidate.
Usually fails on: Fails on minimal arrays and exact-boundary answers.
Fix: Re-derive loops from inclusive/exclusive ranges before coding.
Wrong move: Zero-count keys stay in map and break distinct/count constraints.
Usually fails on: Window/map size checks are consistently off by one.
Fix: Delete keys when count reaches zero.
Wrong move: Temporary multiplications exceed integer bounds.
Usually fails on: Large inputs wrap around unexpectedly.
Fix: Use wider types, modular arithmetic, or rearranged operations.
Wrong move: An incomplete state merges distinct subproblems and caches incorrect answers.
Usually fails on: Correctness breaks on cases that differ only in hidden state.
Fix: Define state so each unique subproblem maps to one DP cell.