Skip to content

Commit

Permalink
feat: add string compression solution
Browse files Browse the repository at this point in the history
  • Loading branch information
sandrig committed Jul 23, 2023
1 parent fa9a08d commit bc47995
Show file tree
Hide file tree
Showing 4 changed files with 182 additions and 0 deletions.
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,9 @@
| 2 | [Move Zeroes](https://leetcode.com/problems/move-zeroes/) | [TypeScript](https://github.com/sandrig/leetcode/blob/master/typescript/src/moveZeroes/README.md) | _O(n)_ | _O(1)_ | Array, Two Pointers |
| 3 | [Valid Palindrome](https://leetcode.com/problems/valid-palindrome/) | [TypeScript](https://github.com/sandrig/leetcode/blob/master/typescript/src/validPalindrome/README.md) | _O(n)_ | _O(n)_ | String, Two Pointers |
| 4 | [Summary Ranges](https://leetcode.com/problems/summary-ranges/) | [TypeScript](https://github.com/sandrig/leetcode/blob/master/typescript/src/summaryRanges/README.md) | _O(n)_ | _O(n)_ | Array |

## Medium

| # | Problem | Solution | Time | Space | Tag |
| --- | ----------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- | ------ | ------ | -------------------- |
| 1 | [String Compression](https://leetcode.com/problems/string-compression/) | [TypeScript](https://github.com/sandrig/leetcode/blob/master/typescript/src/stringCompression/README.md) | _O(n)_ | _O(n)_ | Two Pointers, String |
80 changes: 80 additions & 0 deletions typescript/src/stringCompression/README.md
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 typescript/src/stringCompression/stringCompression.test.ts
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([]);
});
});
30 changes: 30 additions & 0 deletions typescript/src/stringCompression/stringCompression.ts
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;
}

0 comments on commit bc47995

Please sign in to comment.