Hash Tables
First Non-Repeating Value
Find the first input value whose final frequency is one.
Algorithm
Canonical input [3, 5, 2, 5, 3, 8, 2] prints 8.
The replay uses the same input in every language, so this R DSA
implementation can be compared directly with the rest of the DSA track.
two-pass lookup
The first pass builds a frequency table. The second pass keeps the original order and stops at the first value with frequency one.
Basic Implementation
basic.R
Replay: real traced execution (multi-file project)
arr <- c(3, 5, 2, 5, 3, 8, 2)
count <- table(arr)
for (value in arr) {
if (count[as.character(value)] == 1) {
cat(value, "\n", sep = "")
break
}
}
arr ← [3, 5, 2, 5, 3, 8, 2]
1arr <- c(3, 5, 2, 5, 3, 8, 2)2count <- table(arr)values this step[3, 5, 2, 5, 3, 8, 2]arrcount ← {}
1arr <- c(3, 5, 2, 5, 3, 8, 2)2count <- table(arr)3for (value in arr) {values this step{}countcount ← {3: 1}
1arr <- c(3, 5, 2, 5, 3, 8, 2)2count <- table(arr)3for (value in arr) {values this step{} → {3: 1}count3valuecount ← {3: 1, 5: 1}
1arr <- c(3, 5, 2, 5, 3, 8, 2)2count <- table(arr)3for (value in arr) {values this step{3: 1} → {3: 1, 5: 1}count5valuecount ← {3: 1, 5: 1, 2: 1}
1arr <- c(3, 5, 2, 5, 3, 8, 2)2count <- table(arr)3for (value in arr) {values this step{3: 1, 5: 1} → {3: 1, 5: 1, 2: 1}count2valuecount ← {3: 1, 5: 2, 2: 1}
1arr <- c(3, 5, 2, 5, 3, 8, 2)2count <- table(arr)3for (value in arr) {values this step{3: 1, 5: 1, 2: 1} → {3: 1, 5: 2, 2: 1}count5valuecount ← {3: 2, 5: 2, 2: 1}
1arr <- c(3, 5, 2, 5, 3, 8, 2)2count <- table(arr)3for (value in arr) {values this step{3: 1, 5: 2, 2: 1} → {3: 2, 5: 2, 2: 1}count3valuecount ← {3: 2, 5: 2, 2: 1, 8: 1}
1arr <- c(3, 5, 2, 5, 3, 8, 2)2count <- table(arr)3for (value in arr) {values this step{3: 2, 5: 2, 2: 1} → {3: 2, 5: 2, 2: 1, 8: 1}count8valuecount ← {3: 2, 5: 2, 2: 2, 8: 1}
1arr <- c(3, 5, 2, 5, 3, 8, 2)2count <- table(arr)3for (value in arr) {values this step{3: 2, 5: 2, 2: 1, 8: 1} → {3: 2, 5: 2, 2: 2, 8: 1}count2valuei ← 0, value ← 3, count[value] ← 2, found ← no
1arr <- c(3, 5, 2, 5, 3, 8, 2)2count <- table(arr)values this step0i3value2count[value]nofound{3: 2, 5: 2, 2: 2, 8: 1}counti ← 1, value ← 5, count[value] ← 2, found ← no
1arr <- c(3, 5, 2, 5, 3, 8, 2)2count <- table(arr)values this step1i5value2count[value]nofound{3: 2, 5: 2, 2: 2, 8: 1}counti ← 2, value ← 2, count[value] ← 2, found ← no
1arr <- c(3, 5, 2, 5, 3, 8, 2)2count <- table(arr)values this step2i2value2count[value]nofound{3: 2, 5: 2, 2: 2, 8: 1}counti ← 3, value ← 5, count[value] ← 2, found ← no
1arr <- c(3, 5, 2, 5, 3, 8, 2)2count <- table(arr)values this step3i5value2count[value]nofound{3: 2, 5: 2, 2: 2, 8: 1}counti ← 4, value ← 3, count[value] ← 2, found ← no
1arr <- c(3, 5, 2, 5, 3, 8, 2)2count <- table(arr)values this step4i3value2count[value]nofound{3: 2, 5: 2, 2: 2, 8: 1}counti ← 5, value ← 8, count[value] ← 1, found ← yes, result ← 8
1arr <- c(3, 5, 2, 5, 3, 8, 2)2count <- table(arr)values this step5i8value1count[value]yesfound8result{3: 2, 5: 2, 2: 2, 8: 1}countstdout ← 8
4if (count[as.character(value)] == 1) {5 cat(value, "\n", sep = "")6 breakvalues this step8stdout8result
Complexity
- Time: O(n) average
- Space: O(k) for k distinct values
Implementation notes
arr <- c(3, 5, 2, 5, 3, 8, 2)is the pinned R vector for this replay.count <- table(arr)builds R's named frequency table. The trace shows it filling from{}through{3: 1},{3: 1, 5: 1}, and the final{3: 2, 5: 2, 2: 2, 8: 1}.- The second pass uses
for (value in arr), so it checks values in the original vector order instead of walking the table names. table()stores its names as labels, so lookup usescount[as.character(value)]: numeric3is read from the table name"3".- Values
3,5, and2are skipped because their counts are2. - When the pass reaches
8, its count is1;cat(value, "\n", sep = "")prints8, andbreakstops the loop.
Replay steps
counts: {} -> {3:1} -> {3:1,5:1} -> ... -> {3:2,5:2,2:2,8:1}
scan: 3(count 2), 5(count 2), 2(count 2), 5(count 2), 3(count 2)
result: 8(count 1) prints 8