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 two string arrays positive_feedback and negative_feedback, containing the words denoting positive and negative feedback, respectively. Note that no word is both positive and negative.
Initially every student has 0 points. Each positive word in a feedback report increases the points of a student by 3, whereas each negative word decreases the points by 1.
You are given n feedback reports, represented by a 0-indexed string array report and a 0-indexed integer array student_id, where student_id[i] represents the ID of the student who has received the feedback report report[i]. The ID of each student is unique.
Given an integer k, return the top k students after ranking them in non-increasing order by their points. In case more than one student has the same points, the one with the lower ID ranks higher.
Example 1:
Input: positive_feedback = ["smart","brilliant","studious"], negative_feedback = ["not"], report = ["this student is studious","the student is smart"], student_id = [1,2], k = 2 Output: [1,2] Explanation: Both the students have 1 positive feedback and 3 points but since student 1 has a lower ID he ranks higher.
Example 2:
Input: positive_feedback = ["smart","brilliant","studious"], negative_feedback = ["not"], report = ["this student is not studious","the student is smart"], student_id = [1,2], k = 2 Output: [2,1] Explanation: - The student with ID 1 has 1 positive feedback and 1 negative feedback, so he has 3-1=2 points. - The student with ID 2 has 1 positive feedback, so he has 3 points. Since student 2 has more points, [2,1] is returned.
Constraints:
1 <= positive_feedback.length, negative_feedback.length <= 1041 <= positive_feedback[i].length, negative_feedback[j].length <= 100positive_feedback[i] and negative_feedback[j] consists of lowercase English letters.positive_feedback and negative_feedback.n == report.length == student_id.length1 <= n <= 104report[i] consists of lowercase English letters and spaces ' '.report[i].1 <= report[i].length <= 1001 <= student_id[i] <= 109student_id[i] are unique.1 <= k <= nProblem summary: You are given two string arrays positive_feedback and negative_feedback, containing the words denoting positive and negative feedback, respectively. Note that no word is both positive and negative. Initially every student has 0 points. Each positive word in a feedback report increases the points of a student by 3, whereas each negative word decreases the points by 1. You are given n feedback reports, represented by a 0-indexed string array report and a 0-indexed integer array student_id, where student_id[i] represents the ID of the student who has received the feedback report report[i]. The ID of each student is unique. Given an integer k, return the top k students after ranking them in non-increasing order by their points. In case more than one student has the same points, the one with the lower ID ranks higher.
Start with the most direct exhaustive search. That gives a correctness anchor before optimizing.
Pattern signal: Array · Hash Map
["smart","brilliant","studious"] ["not"] ["this student is studious","the student is smart"] [1,2] 2
["smart","brilliant","studious"] ["not"] ["this student is not studious","the student is smart"] [1,2] 2
queue-reconstruction-by-height)k-highest-ranked-items-within-a-price-range)Source-backed implementations are provided below for direct study and interview prep.
// Accepted solution for LeetCode #2512: Reward Top K Students
class Solution {
public List<Integer> topStudents(String[] positive_feedback, String[] negative_feedback,
String[] report, int[] student_id, int k) {
Set<String> ps = new HashSet<>();
Set<String> ns = new HashSet<>();
for (var s : positive_feedback) {
ps.add(s);
}
for (var s : negative_feedback) {
ns.add(s);
}
int n = report.length;
int[][] arr = new int[n][0];
for (int i = 0; i < n; ++i) {
int sid = student_id[i];
int t = 0;
for (var s : report[i].split(" ")) {
if (ps.contains(s)) {
t += 3;
} else if (ns.contains(s)) {
t -= 1;
}
}
arr[i] = new int[] {t, sid};
}
Arrays.sort(arr, (a, b) -> a[0] == b[0] ? a[1] - b[1] : b[0] - a[0]);
List<Integer> ans = new ArrayList<>();
for (int i = 0; i < k; ++i) {
ans.add(arr[i][1]);
}
return ans;
}
}
// Accepted solution for LeetCode #2512: Reward Top K Students
func topStudents(positive_feedback []string, negative_feedback []string, report []string, student_id []int, k int) (ans []int) {
ps := map[string]bool{}
ns := map[string]bool{}
for _, s := range positive_feedback {
ps[s] = true
}
for _, s := range negative_feedback {
ns[s] = true
}
arr := [][2]int{}
for i, sid := range student_id {
t := 0
for _, w := range strings.Split(report[i], " ") {
if ps[w] {
t += 3
} else if ns[w] {
t -= 1
}
}
arr = append(arr, [2]int{t, sid})
}
sort.Slice(arr, func(i, j int) bool { return arr[i][0] > arr[j][0] || (arr[i][0] == arr[j][0] && arr[i][1] < arr[j][1]) })
for _, v := range arr[:k] {
ans = append(ans, v[1])
}
return
}
# Accepted solution for LeetCode #2512: Reward Top K Students
class Solution:
def topStudents(
self,
positive_feedback: List[str],
negative_feedback: List[str],
report: List[str],
student_id: List[int],
k: int,
) -> List[int]:
ps = set(positive_feedback)
ns = set(negative_feedback)
arr = []
for sid, r in zip(student_id, report):
t = 0
for w in r.split():
if w in ps:
t += 3
elif w in ns:
t -= 1
arr.append((t, sid))
arr.sort(key=lambda x: (-x[0], x[1]))
return [v[1] for v in arr[:k]]
// Accepted solution for LeetCode #2512: Reward Top K Students
use std::collections::{HashMap, HashSet};
impl Solution {
pub fn top_students(
positive_feedback: Vec<String>,
negative_feedback: Vec<String>,
report: Vec<String>,
student_id: Vec<i32>,
k: i32,
) -> Vec<i32> {
let n = student_id.len();
let ps = positive_feedback.iter().collect::<HashSet<&String>>();
let ns = negative_feedback.iter().collect::<HashSet<&String>>();
let mut map = HashMap::new();
for i in 0..n {
let id = student_id[i];
let mut count = 0;
for s in report[i].split(' ') {
let s = &s.to_string();
if ps.contains(s) {
count += 3;
} else if ns.contains(s) {
count -= 1;
}
}
map.insert(id, count);
}
let mut t = map.into_iter().collect::<Vec<(i32, i32)>>();
t.sort_by(|a, b| {
if a.1 == b.1 {
return a.0.cmp(&b.0);
}
b.1.cmp(&a.1)
});
t.iter().map(|v| v.0).collect::<Vec<i32>>()[0..k as usize].to_vec()
}
}
// Accepted solution for LeetCode #2512: Reward Top K Students
function topStudents(
positive_feedback: string[],
negative_feedback: string[],
report: string[],
student_id: number[],
k: number,
): number[] {
const n = student_id.length;
const map = new Map<number, number>();
const ps = new Set(positive_feedback);
const ns = new Set(negative_feedback);
for (let i = 0; i < n; i++) {
map.set(
student_id[i],
report[i].split(' ').reduce((r, s) => {
if (ps.has(s)) {
return r + 3;
}
if (ns.has(s)) {
return r - 1;
}
return r;
}, 0),
);
}
return [...map.entries()]
.sort((a, b) => {
if (a[1] === b[1]) {
return a[0] - b[0];
}
return b[1] - a[1];
})
.map(v => v[0])
.slice(0, k);
}
Use this to step through a reusable interview workflow for this problem.
Two nested loops check every pair or subarray. The outer loop fixes a starting point, the inner loop extends or searches. For n elements this gives up to n²/2 operations. No extra space, but the quadratic time is prohibitive for large inputs.
Most array problems have an O(n²) brute force (nested loops) and an O(n) optimal (single pass with clever state tracking). The key is identifying what information to maintain as you scan: a running max, a prefix sum, a hash map of seen values, or two pointers.
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.