-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add string compression solution
- Loading branch information
Showing
4 changed files
with
182 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
# [String Compression](https://leetcode.com/problems/string-compression/) | ||
|
||
## Description | ||
|
||
Given an array of characters **chars**, compress it using the following algorithm: | ||
|
||
Begin with an empty string **s**. For each group of consecutive repeating characters in **chars**: | ||
|
||
- If the group's length is **1**, append the character to **s**. | ||
- Otherwise, append the character followed by the group's length. | ||
|
||
The compressed string **s** should not be returned separately, but instead, be stored in the input character array **chars**. Note that group lengths that are **10** or longer will be split into multiple characters in **chars**. | ||
|
||
After you are done modifying the input array, return the new length of the array. | ||
|
||
You must write an algorithm that uses only constant extra space. | ||
|
||
**Example 1:** | ||
|
||
``` | ||
Input: chars = ["a","a","b","b","c","c","c"] | ||
Output: Return 6, and the first 6 characters of the input array should be: ["a","2","b","2","c","3"] | ||
Explanation: The groups are "aa", "bb", and "ccc". This compresses to "a2b2c3". | ||
``` | ||
|
||
**Example 2:** | ||
|
||
``` | ||
Input: chars = ["a"] | ||
Output: Return 1, and the first character of the input array should be: ["a"] | ||
Explanation: The only group is "a", which remains uncompressed since it's a single character. | ||
``` | ||
|
||
**Example 3:** | ||
|
||
``` | ||
Input: chars = ["a","b","b","b","b","b","b","b","b","b","b","b","b"] | ||
Output: Return 4, and the first 4 characters of the input array should be: ["a","b","1","2"]. | ||
Explanation: The groups are "a" and "bbbbbbbbbbbb". This compresses to "ab12". | ||
``` | ||
|
||
## Solution | ||
|
||
```typescript | ||
function compress(chars: string[]): number { | ||
let writeIndex = 0; // Index to write compressed characters | ||
let readIndex = 0; // Index to read source characters | ||
|
||
while (readIndex < chars.length) { | ||
const currentChar = chars[readIndex]; | ||
let count = 0; | ||
|
||
// Counting the number of repeated characters | ||
while (readIndex < chars.length && chars[readIndex] === currentChar) { | ||
readIndex++; | ||
count++; | ||
} | ||
|
||
// Write a compressed character | ||
chars[writeIndex] = currentChar; | ||
writeIndex++; | ||
|
||
// If the character is repeated more than once, record the number of repetitions | ||
if (count > 1) { | ||
for (const digit of count.toString().split("")) { | ||
chars[writeIndex] = digit; | ||
writeIndex++; | ||
} | ||
} | ||
} | ||
|
||
// Returning the new length of the compressed string | ||
return writeIndex; | ||
} | ||
``` | ||
|
||
## Complexity Analysis | ||
|
||
- Time complexity: _O(n)_ | ||
- Space complexity: _O(n)_ |
66 changes: 66 additions & 0 deletions
66
typescript/src/stringCompression/stringCompression.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
import { compress } from "./stringCompression"; | ||
|
||
describe("String Compression", () => { | ||
it("should compress the string with repeated characters", () => { | ||
const chars: string[] = ["a", "a", "b", "b", "c", "c", "c"]; | ||
const compressedLength = compress(chars); | ||
expect(compressedLength).toBe(6); | ||
expect(chars.slice(0, compressedLength)).toEqual([ | ||
"a", | ||
"2", | ||
"b", | ||
"2", | ||
"c", | ||
"3", | ||
]); | ||
}); | ||
|
||
it("should return the original string if it cannot be compressed", () => { | ||
const chars: string[] = ["a"]; | ||
const compressedLength = compress(chars); | ||
expect(compressedLength).toBe(1); | ||
expect(chars.slice(0, compressedLength)).toEqual(["a"]); | ||
}); | ||
|
||
it("should handle multiple repeating characters", () => { | ||
const chars: string[] = [ | ||
"a", | ||
"b", | ||
"b", | ||
"b", | ||
"b", | ||
"b", | ||
"b", | ||
"b", | ||
"b", | ||
"b", | ||
"b", | ||
"b", | ||
"b", | ||
]; | ||
const compressedLength = compress(chars); | ||
expect(compressedLength).toBe(4); | ||
expect(chars.slice(0, compressedLength)).toEqual(["a", "b", "1", "2"]); | ||
}); | ||
|
||
it("should handle alternating characters", () => { | ||
const chars: string[] = ["a", "a", "a", "b", "b", "a", "a"]; | ||
const compressedLength = compress(chars); | ||
expect(compressedLength).toBe(6); | ||
expect(chars.slice(0, compressedLength)).toEqual([ | ||
"a", | ||
"3", | ||
"b", | ||
"2", | ||
"a", | ||
"2", | ||
]); | ||
}); | ||
|
||
it("should handle an empty string", () => { | ||
const chars: string[] = []; | ||
const compressedLength = compress(chars); | ||
expect(compressedLength).toBe(0); | ||
expect(chars.slice(0, compressedLength)).toEqual([]); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
export function compress(chars: string[]): number { | ||
let writeIndex = 0; // Index to write compressed characters | ||
let readIndex = 0; // Index to read source characters | ||
|
||
while (readIndex < chars.length) { | ||
const currentChar = chars[readIndex]; | ||
let count = 0; | ||
|
||
// Counting the number of repeated characters | ||
while (readIndex < chars.length && chars[readIndex] === currentChar) { | ||
readIndex++; | ||
count++; | ||
} | ||
|
||
// Write a compressed character | ||
chars[writeIndex] = currentChar; | ||
writeIndex++; | ||
|
||
// If the character is repeated more than once, record the number of repetitions | ||
if (count > 1) { | ||
for (const digit of count.toString().split("")) { | ||
chars[writeIndex] = digit; | ||
writeIndex++; | ||
} | ||
} | ||
} | ||
|
||
// Returning the new length of the compressed string | ||
return writeIndex; | ||
} |