THE WEEKLY CHALLENGE - 237

https://theweeklychallenge.org/blog/perl-weekly-challenge-237/

Table of Contents

Task 1 - Seize the day

Today, we'll be tackling an interesting problem: given a year, a month, a weekday of the month, and a day of the week, we want to find out the exact date that corresponds to these details. Specifically, the task is to determine the day of the month for the Nth occurrence of a specific weekday in a specific month and year.

The Problem Statement

The problem is simple yet intriguing. Given a year, month, weekday of the month (1st, 2nd, 3rd, etc.), and a day of the week (1 for Monday, 2 for Tuesday, ..., 7 for Sunday), the task is to find the exact day of the month that corresponds to these parameters.

For example, if the year is 2024, the month is April, the weekday of the month is 3rd, and the day of the week is Tuesday (2), the corresponding date is the 16th of April 2024.

Algorithmic Approach

  1. Step 1: Calculate the day of the week for the first day of the given month and year.
  2. Step 2: Determine the difference in days between this day of the week and the desired day of the week.
  3. Step 3: Use this difference to find the date of the first occurrence of the desired day of the week in the given month.
  4. Step 4: Add (N - 1) * 7 days to this date to find the Nth occurrence.
  5. Step 5: If the resulting date still falls within the same month, then it's a valid date; otherwise, return 0.

Perl Solution

In Perl, we use the Time::Local module to calculate the day of the week for the first day of the given month and year.

Here is a snippet of the Perl code:

# Calculate the timestamp for the first day of the month
my $first_day = timelocal(0, 0, 0, 1, $month - 1, $year);

# Calculate the day of the week for the first day of the month
my $first_day_of_week = (localtime($first_day))[6];

# Calculate the difference in days to reach the desired day of the week
my $days_diff = ($day_of_week - $first_day_of_week) % 7;

# Calculate the timestamp for the nth occurrence
my $nth_occurrence = $first_occurrence + (($weekday_of_month - 1) * 7 * 86400);

Raku Solution

In Raku, the Date class provides an easy way to work with dates. We can create a Date object for the first day of the given month and year and use its .day-of-week method to get the day of the week.

Here's a snippet of the Raku code:

# Calculate the day of the week for the first day of the month
my $first-day-of-week = Date.new($year, $month, 1).day-of-week;

# Calculate the difference in days to reach the desired day of the week
my $days-diff = ($day-of-week - $first-day-of-week) % 7;

# Calculate the nth occurrence
my $nth-occurrence = 1 + $days-diff + ($weekday-of-month - 1) * 7;

Python Solution

In Python, we can use the datetime module to achieve the same. Here's a snippet:

from datetime import datetime, timedelta

# Calculate the day of the week for the first day of the month
first_day_of_week = datetime(year, month, 1).weekday()

# Calculate the difference in days to reach the desired day of the week
days_diff = (day_of_week - first_day_of_week - 1) % 7

# Calculate the nth occurrence
nth_occurrence = 1 + days_diff + (weekday_of_month - 1) * 7

Conclusion

By understanding how to manipulate dates and times in different programming languages, we can solve a variety of real-world problems. This problem is just one example, but the techniques used can be applied in many other situations.


Task 2 - Maximise Greatness

Problem Statement

Given an array of integers, the task is to permute the array in such a way that we get the maximum possible "greatness" score. The greatness score is calculated as follows: For each index ( i ) in the array, if ( array[i] < perm[i] ), we increment the greatness score by 1.

For example, given the array ([1, 3, 5, 2, 1, 3, 1]), one possible permutation with maximum greatness is ([2, 5, 1, 3, 3, 1, 1]), yielding a greatness score of 4.

Algorithm

The algorithm is quite simple:

  1. Sort the array in ascending order.
  2. Iterate through the original array and for each element:
    • Find the smallest element in the sorted array that is greater than the current element.
    • Remove that element from the sorted array.
    • Increment the greatness counter.

Perl Solution

In Perl, we use the splice function to remove an element from the sorted array.

sub maximise_greatness {
    my @nums = @_;
    my @sorted_nums = sort { $a <=> $b } @nums;
    my $greatness = 0;

    for my $num (@nums) {
        for my $i (0..$#sorted_nums) {
            if ($sorted_nums[$i] > $num) {
                $greatness++;
                splice(@sorted_nums, $i, 1);
                last;
            }
        }
    }
    return $greatness;
}

Python Solution

In Python, we use the remove method to remove an element from the sorted array.

def maximise_greatness(nums):
    sorted_nums = sorted(nums)
    greatness = 0

    for num in nums:
        for i in range(len(sorted_nums)):
            if sorted_nums[i] > num:
                greatness += 1
                sorted_nums.pop(i)
                break
    return greatness

Raku Solution

In Raku, we use the splice method to remove an element from the sorted array.

sub maximise-greatness(@nums) {
    my @sorted-nums = @nums.sort({ $^a <=> $^b });
    my $greatness = 0;

    for @nums -> $num {
        for 0..^@sorted-nums.elems -> $i {
            if @sorted-nums[$i] > $num {
                $greatness++;
                @sorted-nums.splice($i, 1);
                last;
            }
        }
    }
    return $greatness;
}

Conclusion

The problem of maximizing greatness in an array can be efficiently solved in Perl, Python, and Raku with slight variations in syntax but keeping the core algorithm the same. All three languages offer efficient ways to manipulate arrays, making it easy to implement the solution.