Home/ BACKEND/ Weekly Coding Challenge: Solutions in Python and Perl for Uncommon Words and Outermost Parentheses

Weekly Coding Challenge: Solutions in Python and Perl for Uncommon Words and Outermost Parentheses

Explore Simon Green's solutions to The Weekly Challenge 385: finding uncommon words and removing outermost parentheses, with implementation in both P…

David Parkverified
David Park
2h ago11 min read
Listen to this article
Weekly Coding Challenge: Solutions in Python and Perl for Uncommon Words and Outermost Parentheses

The Weekly Challenge, a popular initiative among developers, recently presented its 385th iteration, offering two distinct programming tasks designed to sharpen algorithmic thinking and coding proficiency. This article delves into robust Weekly Challenge coding solutions for both tasks, “Uncommon Words” and “Outermost Parentheses,” providing implementations in Python and Perl. By examining these solutions, developers can gain insights into different approaches, language-specific idioms, and considerations for efficient problem-solving.

  • The Weekly Challenge 385 featured “Uncommon Words” and “Outermost Parentheses,” offering practical algorithmic exercises.
  • Python and Perl solutions demonstrate varied approaches to string manipulation, data structures, and conditional logic.
  • Understanding edge cases and optimizing for performance are crucial aspects of developing robust coding solutions.
  • Comparing solutions across languages highlights language-specific strengths and common algorithmic patterns.

The Weekly Challenge 385: An Overview

The Weekly Challenge (TWC) has established itself as a valuable resource for developers seeking to hone their problem-solving skills and explore diverse programming paradigms. Each week, participants are presented with two distinct tasks, ranging from string manipulation and array processing to more complex algorithmic puzzles. TWC 385 maintained this tradition by offering challenges that, while seemingly straightforward, required careful consideration of data structures and control flow. The community aspect, where developers share and discuss their solutions across various languages, significantly enhances the learning experience. More information about the challenge can be found on The Weekly Challenge official website.

Task 1: Uncommon Words

The first task, “Uncommon Words,” presented a classic text processing problem, challenging participants to identify words unique to one of two given sentences. This type of problem often serves as an excellent introduction to string manipulation, set operations, and frequency counting.

Problem Statement: Uncommon Words

Given two sentences, $S1 and $S2, find all uncommon words. An uncommon word is a word that appears exactly once in one of the sentences and does not appear in the other sentence. The order of the output words does not matter.

For example, if $S1 = "this apple is sweet" and $S2 = "this apple is sour", the uncommon words are ["sweet", "sour"].

Python Solution for Uncommon Words

Python offers powerful tools for text processing, making it well-suited for this task. The collections.Counter class is particularly effective for counting word frequencies. The approach involves counting words in each sentence, identifying words that appear exactly once, and then checking for their absence in the other sentence.

Here’s a Python solution:

from collections import Counter

def uncommon_words(s1: str, s2: str) -> list[str]:
    words1 = s1.lower().split()
    words2 = s2.lower().split()

    count1 = Counter(words1)
    count2 = Counter(words2)

    uncommon = []

    for word, count in count1.items():
        if count == 1 and word not in count2:
            uncommon.append(word)

    for word, count in count2.items():
        if count == 1 and word not in count1:
            uncommon.append(word)

    return uncommon

# Example Usage:
s1_example = "this apple is sweet"
s2_example = "this apple is sour"
print(f"Uncommon words: {uncommon_words(s1_example, s2_example)}")

s3_example = "apple apple"
s4_example = "banana"
print(f"Uncommon words: {uncommon_words(s3_example, s4_example)}")

The Python solution first converts sentences to lowercase and splits them into words. It then uses Counter to efficiently get word frequencies. The logic iterates through each Counter, appending words that appear once and are not present in the other sentence’s Counter. This method is concise and leverages Python’s built-in data structures effectively. For more details on collections.Counter, refer to the Python documentation.

Perl Solution for Uncommon Words

Perl, known for its strong text processing capabilities, provides a different yet equally effective approach. Regular expressions and hash maps (Perl’s hashes) are central to the solution.

Here’s a Perl solution, adapted from community submissions like those found on Perl Weekly Challenge GitHub:

use strict;
use warnings;

sub uncommon_words {
    my ($s1, $s2) = @_;

    my %count1;
    foreach my $word (split /\s+/, lc $s1) {
        $count1{$word}++;
    }

    my %count2;
    foreach my $word (split /\s+/, lc $s2) {
        $count2{$word}++;
    }

    my @uncommon;

    foreach my $word (keys %count1) {
        if ($count1{$word} == 1 && !exists $count2{$word}) {
            push @uncommon, $word;
        }
    }

    foreach my $word (keys %count2) {
        if ($count2{$word} == 1 && !exists $count1{$word}) {
            push @uncommon, $word;
        }
    }

    return @uncommon;
}

# Example Usage:
my $s1_example = "this apple is sweet";
my $s2_example = "this apple is sour";
my @result = uncommon_words($s1_example, $s2_example);
print "Uncommon words: @result\n";

my $s3_example = "apple apple";
my $s4_example = "banana";
@result = uncommon_words($s3_example, $s4_example);
print "Uncommon words: @result\n";

The Perl solution mirrors the Pythonic approach by utilizing hashes to store word frequencies. It converts sentences to lowercase and splits them using regular expressions. The subsequent loops check frequencies and existence in the other hash to identify and collect uncommon words. For developers working with Perl, understanding these hash operations is fundamental. You can find more Perl for Developers resources to deepen your knowledge.

Analysis of Uncommon Words Solutions

Both Python and Perl solutions for “Uncommon Words” demonstrate effective use of hash-based data structures for frequency counting. Python’s collections.Counter provides a slightly more abstracted and potentially more readable way to achieve this, while Perl’s explicit hash manipulation offers fine-grained control. Performance-wise, both approaches are efficient, operating in approximately linear time relative to the total number of words, as hash lookups and insertions are, on average, O(1).

Edge cases to consider include empty sentences, sentences with only common words, and sentences with repeated uncommon words. Both solutions handle these cases gracefully due to their reliance on frequency counts and existence checks. For instance, if a word appears twice in S1 but not in S2, it would not be considered uncommon because its count in count1 would be 2.

Task 2: Outermost Parentheses

The second task, “Outermost Parentheses,” delves into string parsing and stack-like logic, a common theme in programming challenges involving balanced symbols.

Problem Statement: Outermost Parentheses

A valid parentheses string S is primitive if it is non-empty, and there does not exist a way to split it into S = A + B, where A and B are non-empty valid parentheses strings. A valid parentheses string S has a primitive decomposition S = P1 + P2 + ... + Pk, where each Pi is a primitive valid parentheses string. Given a valid parentheses string S, return S after removing the outermost parentheses of every primitive string in the primitive decomposition of S.

For example, if S = "(()())(())", its primitive decomposition is "(()())" + "(())". Removing the outermost parentheses from each results in "()()" + "()". The final output should be "()()()".

Python Solution for Outermost Parentheses

This problem can be elegantly solved using a counter to track the balance of parentheses. When the counter is at 0, it signifies the boundary of a primitive string (or the start of the entire string). We only append characters when the counter is greater than 1 for an opening parenthesis and greater than 0 for a closing parenthesis, effectively skipping the outermost ones.

Here’s a Python solution:

def remove_outermost_parentheses(s: str) -> str:
    result = []
    balance = 0
    for char in s:
        if char == '(':
            if balance > 0:
                result.append(char)
            balance += 1
        elif char == ')':
            balance -= 1
            if balance > 0:
                result.append(char)
    return "".join(result)

# Example Usage:
s_example1 = "(()())(())"
print(f"Result for '{s_example1}': {remove_outermost_parentheses(s_example1)}") # Expected: ()()()

s_example2 = "(()(()))"
print(f"Result for '{s_example2}': {remove_outermost_parentheses(s_example2)}") # Expected: ()(())

s_example3 = "()()"
print(f"Result for '{s_example3}': {remove_outermost_parentheses(s_example3)}") # Expected: ""

The Python solution uses a balance counter. When an opening parenthesis ( is encountered, if balance is already greater than 0 (meaning it’s not the outermost of a primitive string), it’s appended to the result. The balance is then incremented. For a closing parenthesis ), the balance is decremented first, and if it’s still greater than 0 (meaning it’s not the outermost closing parenthesis), it’s appended. This logic correctly identifies and skips the outermost parentheses of each primitive string. This is a good example of Python Code Examples for string manipulation.

Perl Solution for Outermost Parentheses

Perl can also solve this using a similar counter-based approach. The syntax differs, but the underlying logic of tracking the balance remains the same.

use strict;
use warnings;

sub remove_outermost_parentheses {
    my ($s) = @_;
    my $result = "";
    my $balance = 0;
    foreach my $char (split //, $s) {
        if ($char eq '(') {
            if ($balance > 0) {
                $result .= $char;
            }
            $balance++;
        } elsif ($char eq ')') {
            $balance--;
            if ($balance > 0) {
                $result .= $char;
            }
        }
    }
    return $result;
}

# Example Usage:
my $s_example1 = "(()())(())";
print "Result for '$s_example1': " . remove_outermost_parentheses($s_example1) . "\n"; # Expected: ()()()

my $s_example2 = "(()(()))";
print "Result for '$s_example2': " . remove_outermost_parentheses($s_example2) . "\n"; # Expected: ()(())

my $s_example3 = "()()";
print "Result for '$s_example3': " . remove_outermost_parentheses($s_example3) . "\n"; # Expected: ""

The Perl solution iterates through the string character by character. It maintains a $balance variable, incrementing for ( and decrementing for ). The appending logic is identical to the Python version: only append an opening parenthesis if $balance is positive before incrementing, and only append a closing parenthesis if $balance is positive after decrementing. This ensures that the first ( and last ) of each primitive component are omitted.

Analysis of Outermost Parentheses Solutions

Both Python and Perl solutions for “Outermost Parentheses” are highly efficient, processing the input string in a single pass. This translates to a time complexity of O(N), where N is the length of the string, as each character is visited exactly once. The space complexity is O(N) in the worst case for the result string, though it could be considered O(1) auxiliary space if the output string construction is not counted.

A key aspect of this problem is understanding the definition of a “primitive” valid parentheses string. The counter method implicitly identifies these primitive components by tracking when the balance returns to zero. When the balance is zero, a complete primitive string has just been processed (or the string is just starting), and the next opening parenthesis signals the beginning of a new primitive string. This approach effectively bypasses the need for explicit stack data structures, simplifying the implementation while maintaining correctness.

The Broader Implications of Coding Challenges

Weekly coding challenges like those from TWC offer more than just an opportunity to solve puzzles; they provide a structured environment for continuous learning and skill refinement. For individual developers, regularly tackling these problems reinforces fundamental algorithmic concepts, introduces new language features, and encourages exploration of different problem-solving strategies. The act of translating a problem description into working code across different languages, as demonstrated with Python and Perl, also highlights the universality of certain algorithmic patterns while showcasing language-specific strengths and idiomatic expressions.

From an industry perspective, participation in such challenges can contribute to a developer’s portfolio and demonstrate practical coding abilities, which are highly valued in technical roles. The exposure to diverse problem types, including string manipulation, data structure optimization, and logical reasoning, prepares developers for real-world scenarios where these skills are routinely applied. Furthermore, the community aspect fosters collaborative learning and provides a platform for receiving feedback and discovering alternative, potentially more efficient, solutions from peers. This continuous engagement with problem-solving cultivates a growth mindset essential for navigating the rapidly evolving landscape of software development.

FAQ: Frequently Asked Questions

What is The Weekly Challenge?
The Weekly Challenge is a programming initiative that presents two coding tasks each week, encouraging developers to solve them in their preferred programming language and share their solutions with a global community.
Why are coding challenges important for developers?
Coding challenges help developers improve their algorithmic thinking, problem-solving skills, learn new language features, and stay updated with various programming paradigms. They also provide practical experience that can be valuable in professional development.
How do I handle case sensitivity in word-based challenges?
Typically, words are converted to a consistent case (e.g., lowercase) before processing to ensure that “Apple” and “apple” are treated as the same word, unless the problem statement specifies case sensitivity.
What are “primitive” valid parentheses strings?
A primitive valid parentheses string is a non-empty, balanced parentheses string that cannot be broken down into two smaller, non-empty valid parentheses strings. For example, “()” is primitive, but “()()” is not (it’s “()” + “()”).

Conclusion

The Weekly Challenge 385 provided two insightful tasks, “Uncommon Words” and “Outermost Parentheses,” which served as excellent exercises in string processing and algorithmic logic. The Python and Perl solutions presented highlight how different languages can effectively tackle the same problems, leveraging their unique features while adhering to core programming principles. Mastering these types of challenges is not merely about finding the correct answer but understanding the underlying data structures, algorithmic choices, and potential edge cases. Continuous engagement with such coding exercises is invaluable for any developer aiming to enhance their craft and deepen their understanding of computer science fundamentals.

folder_openBACKEND schedule11 min read eventPublished personDavid Park
David Park
Written by David Park

David Park is DailyTech.dev's senior developer-tools writer with 8+ years of full-stack engineering experience. He covers the modern developer toolchain — VS Code, Cursor, GitHub Copilot, Vercel, Supabase — alongside the languages and frameworks shaping production code today. His expertise spans TypeScript, Python, Rust, AI-assisted coding workflows, CI/CD pipelines, and developer experience. Before joining DailyTech.dev, David shipped production applications for several startups and a Fortune-500 company. He personally tests every IDE, framework, and AI coding assistant before reviewing it, follows the GitHub trending feed daily, and reads release notes from the major language ecosystems. When not benchmarking the latest agentic coder or migrating a monorepo, David is contributing to open-source — first-hand using the tools he writes about for working developers.

Join the Conversation

0 Comments

Leave a Reply

No comments yet. Be the first to share your thoughts!