programming challenge – LeetCode: Find And Replace in String C#

It took me a while to solve this question and there are corner cases i missed hence the 4 unit tests.
please review for performance. and if you can treat this as a review for a 45 mins programming interview.

https://leetcode.com/problems/find-and-replace-in-string/

To some string S, we will perform some replacement operations that
replace groups of letters with new ones (not necessarily the same
size).

Each replacement operation has 3 parameters: a starting index i, a
source word x and a target word y. The rule is that if x starts at
position i in the original string S, then we will replace that
occurrence of x with y. If not, we do nothing.

For example, if we have S = “abcd” and we have some replacement
operation i = 2, x = “cd”, y = “ffff”, then because “cd” starts at
position 2 in the original string S, we will replace it with “ffff”.

Using another example on S = “abcd”, if we have both the replacement
operation i = 0, x = “ab”, y = “eee”, as well as another replacement
operation i = 2, x = “ec”, y = “ffff”, this second operation does
nothing because in the original string S(2) = ‘c’, which doesn’t match
x(0) = ‘e’.

All these operations occur simultaneously. It’s guaranteed that there
won’t be any overlap in replacement: for example, S = “abc”, indexes =
(0, 1), sources = (“ab”,”bc”) is not a valid test case.

Example 1:

Input: S = “abcd”, indexes = (0,2), sources = (“a”,”cd”), targets =
(“eee”,”ffff”) Output: “eeebffff” Explanation: “a” starts at index 0
in S, so it’s replaced by “eee”. “cd” starts at index 2 in S, so it’s
replaced by “ffff”. Example 2:

Input: S = “abcd”, indexes = (0,2), sources = (“ab”,”ec”), targets =
(“eee”,”ffff”) Output: “eeecd” Explanation: “ab” starts at index 0 in
S, so it’s replaced by “eee”. “ec” doesn’t starts at index 2 in the
original S, so we do nothing. Notes:

0 <= indexes.length = sources.length = targets.length <= 100 0 <
indexes(i) < S.length <= 1000 All characters in given inputs are
lowercase letters.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace StringQuestions
{      
    (TestClass)
    public class FindReplaceStringTest
    {
        (TestMethod)
        public void TestMethod1()
        {
            string S = "abcd";
            int() indexes = { 0, 2 };
            string() sources = { "a", "cd" };
            string() targets = { "eee", "ffff" };
            string output = "eeebffff";
            Assert.AreEqual(output, FindReplaceStringClass.FindReplaceString(S, indexes, sources, targets));
        }


        (TestMethod)
        public void TestFailMethod1()
        {
            string S = "abcd";
            int() indexes = { 0, 2 };
            string() sources = { "ab", "ec" };
            string() targets = { "eee", "ffff" };
            string output = "eeecd";
            Assert.AreEqual(output, FindReplaceStringClass.FindReplaceString(S, indexes, sources, targets));

        }

        (TestMethod)
        public void TestFailMethod2()
        {
            string S = "vmokgggqzp";
            int() indexes = { 3, 5, 1 };
            string() sources = { "kg", "ggq", "mo" };
            string() targets = { "s", "so", "bfr" };
            string output = "vbfrssozp";
            Assert.AreEqual(output, FindReplaceStringClass.FindReplaceString(S, indexes, sources, targets));
        }

        (TestMethod)
        public void TestFailMethod3()
        {
            string S = "jjievdtjfb";
            int() indexes = { 4,6,1 };
            string() sources = { "md", "tjgb", "jf" };
            string() targets = { "foe", "oov", "e" };
            string output = "jjievdtjfb";
            Assert.AreEqual(output, FindReplaceStringClass.FindReplaceString(S, indexes, sources, targets));
        }
        
    }
}

public class FindReplaceStringClass
{
    public static string FindReplaceString(string S, int() indexes, string() sources, string() targets)
    {
        var index2strings = new SortedDictionary<int, Tuple<string, string>>();
        for (int i = 0; i < indexes.Length; i++)
        {
            index2strings.Add(indexes(i), new Tuple<string, string>(sources(i), targets(i)));
        }

        StringBuilder res = new StringBuilder();
        int curr = 0;//current s pointer
        foreach (var item in index2strings)
        {
            var index = item.Key;
            var source = item.Value.Item1;
            var target = item.Value.Item2;
            //check each index if source appears in s
            for (int k = curr; k < index; k++)
            {
                res.Append(S(k));
                curr++;
            }
            //check the entire prefix is found
            bool isFound = true;
            for (int sIndx = index, j = 0; sIndx < index + source.Length; sIndx++, j++)
            {
                if (S(sIndx) != source(j))
                {
                    isFound = false;
                    break;
                }
            }
            if (!isFound)
            {
                continue;
            }
            curr = index + source.Length;
            //append new string
            foreach (var t in target)
            {
                res.Append(t);
            }
        }
        //the rest of s
        for (int i = curr; i < S.Length; i++)
        {
            res.Append(S(i));
        }
        return res.ToString();
    }

}

algorithms – Why do we need MinHeap for Meeting Rooms 2 Leetcode problem

I came across this problem online which is a Leetcode premium problem. Most of the people are solving this using Minheap. To me using minHeap for this seems like repetitive way to solve a problem if we can achieve the same thing just by sorting the array based on startTimes & than checking if meeting(i).endTime > meeting(i+1).startTime. Increment if the aforementioned condition is true.

I don’t have access to leetcode premium so I can’t verify if the following solution would suffice.
Am I missing something here?

Problem Statement:
enter image description here

public int minMeetingRooms(List<Interval> intervals) {
        // Write your code here
        
        if(intervals == null || intervals.size() == 0)
            return 0;
            
        Collections.sort(intervals, (meeting1, meeting2) -> meeting1.start-meeting2.start);
        
        int rooms = 1;
        
        for(int i=0; i<intervals.size()-1; i++) {
            if(intervals.get(i).end > intervals.get(i+1).start)
                rooms++;
        }
        
        System.out.println("rooms required: "+ rooms);
        
        return rooms;
    }

c++ – LeetCode 1263: Minimum Moves to Move a Box to Their Target Location ||

I’m posting a follow-up code on this question, which seems to be a basic version of Sokoban.

enter image description here

If you’d like to review, please do so. Thank you for your time!

Problem

Storekeeper is a game in which the player pushes boxes around in a warehouse trying to get them to target locations.

The game is represented by a grid of size m x n, where each element is a wall, floor, or a box.

Your task is move the box ‘B’ to the target position ‘T’ under the following rules:

  • Player is represented by character ‘S’ and can move up, down, left, right in the grid if it is a floor (empty cell).
  • Floor is represented by character ‘.’ that means free cell to walk.
  • Wall is represented by character “https://codereview.stackexchange.com/#” that means obstacle (impossible to walk there).
  • There is only one box ‘B’ and one target cell ‘T’ in the grid.
  • The box can be moved to an adjacent free cell by standing next to the box and then moving in the direction of the box. This is a push.
  • The player cannot walk through the box.
  • Return the minimum number of pushes to move the box to the target. If there is no way to reach the target, return -1.

Example 1:

enter image description here

Image Courtesy of LeetCode.com

Input: grid = (("#","#","#","#","#","#"),
               ("#","T","#","#","#","#"),
               ("#",".",".","B",".","#"),
               ("#",".","#","#",".","#"),
               ("#",".",".",".","S","#"),
               ("#","#","#","#","#","#"))
Output: 3
Explanation: We return only the number of times the box is pushed.

Example 2:

Input: grid = (("#","#","#","#","#","#"),
               ("#","T","#","#","#","#"),
               ("#",".",".","B",".","#"),
               ("#","#","#","#",".","#"),
               ("#",".",".",".","S","#"),
               ("#","#","#","#","#","#"))
Output: -1

Example 3:

Input: grid = (("#","#","#","#","#","#"),
               ("#","T",".",".","#","#"),
               ("#",".","#","B",".","#"),
               ("#",".",".",".",".","#"),
               ("#",".",".",".","S","#"),
               ("#","#","#","#","#","#"))
Output: 5
Explanation:  push the box down, left, left, up and up.

Example 4:

Input: grid = (("#","#","#","#","#","#","#"),
               ("#","S","#",".","B","T","#"),
               ("#","#","#","#","#","#","#"))
Output: -1

Constraints:

  • m == grid.length
  • n == grid(i).length
  • 1 <= m <= 20
  • 1 <= n <= 20
  • grid contains only characters ‘.’, “https://codereview.stackexchange.com/#”, ‘S’ , ‘T’, or ‘B’.
  • There is only one character ‘S’, ‘B’ and ‘T’ in the grid.

Code

#include <cstdint>
#include <array>
#include <vector>
#include <utility>
#include <queue>
#include <unordered_set>

class Solution {
    using size_type = std::int_fast16_t;
    static constexpr char kPLAYER = 'S';
    static constexpr char kBOX = 'B';
    static constexpr char kTARGET = 'T';
    static constexpr char kWALL = "https://codereview.stackexchange.com/#";
    static constexpr char kFLOOR = '.';
    static constexpr size_type kDIRECTIONS(4)(2) = {{ -1, 0}, {1, 0}, {0, -1}, {0, 1}};

public:
    int minPushBox(std::vector<std::vector<char>>& grid) {
        const size_type row_len = grid.size();
        const size_type col_len = grid(0).size();

        std::queue<std::pair<size_type, size_type>> player_box_q;


        std::unordered_set<std::pair<size_type, size_type>, player_box_hash> box_player_visited;

        size_type start = 0;
        size_type end = 0;
        size_type player_pos = 0;

        for (size_type row = 0; row < row_len; ++row) {
            for (size_type col = 0; col < col_len; ++col) {
                const size_type curr_pos = row * col_len + col;
                setCurrentPosition(grid, row, col, curr_pos, start, end, player_pos);
            }
        }

        if (start == end) {
            return 0;
        }

        player_box_q.push({start, player_pos});
        size_type pushes = 0;

        while (player_box_q.size()) {
            size_type qlen = player_box_q.size();

            while (qlen--) {
                const auto (box_pos, player_pos) = player_box_q.front();
                player_box_q.pop();

                if (box_pos == end) {
                    return pushes;
                }

                const size_type x_box = box_pos / col_len;
                const size_type y_box = box_pos % col_len;

                for (const auto& direction : kDIRECTIONS) {
                    const size_type next_x_box = x_box + direction(0);
                    const size_type next_y_box = y_box + direction(1);
                    const size_type next_x_player = x_box - direction(0);
                    const size_type next_y_player = y_box - direction(1);

                    if (!isValidPosition(next_x_box, next_y_box, row_len, col_len, grid) || !isValidPosition(next_x_player, next_y_player, row_len, col_len, grid)) {
                        continue;
                    }

                    auto box_player_encode = std::make_pair(box_pos, next_x_player * col_len + next_y_player);


                    if (box_player_visited.count(box_player_encode)) {
                        continue;
                    }

                    if (isAccessible(grid, player_pos, next_x_player * col_len + next_y_player, box_pos)) {
                        player_box_q.push({next_x_box * col_len + next_y_box, box_pos});
                        box_player_visited.insert(box_player_encode);
                    }
                }
            }

            ++pushes;
        }

        return -1;
    }

private:
    struct player_box_hash {
        std::size_t operator()(const std::pair<size_type, size_type>& key) const {
            return std::hash<size_type> {}(size_type(key.first) << 8 | key.second);
        }
    };

    static bool isValidPosition(
        const size_type x,
        const size_type y,
        const size_type& col_len,
        const size_type& row_len,
        const std::vector<std::vector<char>>& grid
    ) {
        return x >= 0 && x < col_len && y >= 0 && y < row_len && grid(x)(y) != kWALL;
    }

    static void setCurrentPosition(
        std::vector<std::vector<char>>& grid,
        const size_type& row,
        const size_type& col,
        const size_type& curr_pos,
        size_type& start,
        size_type& end,
        size_type& player_pos
        

    ) {
        if (grid(row)(col) == kPLAYER) {
            player_pos = curr_pos;
            grid(row)(col) = kFLOOR;
        }

        if (grid(row)(col) == kBOX) {
            start = curr_pos;
            grid(row)(col) = kFLOOR;
        }

        if (grid(row)(col) == kTARGET) {
            end = curr_pos;
            grid(row)(col) = kFLOOR;
        }
    }

    static bool isAccessible(
        std::vector<std::vector<char>>& grid,
        const size_type start,
        const size_type end,
        const size_type box
    ) {
        const size_type row_len = grid.size();
        const size_type col_len = grid(0).size();
        std::queue<size_type> start_q;
        std::vector<bool> valids(row_len * col_len);
        start_q.push(start);
        valids(start) = true;
        grid(box / col_len)(box % col_len) = kWALL;

        while (start_q.size()) {
            size_type qlen = start_q.size();

            while (qlen--) {
                const size_type curr = start_q.front();
                start_q.pop();

                if (curr == end) {
                    grid(box / col_len)(box % col_len) = kFLOOR;
                    return true;
                }

                const size_type x_start = curr / col_len;
                const size_type y_start = curr % col_len;

                for (const auto& direction : kDIRECTIONS) {
                    const size_type x_next = x_start + direction(0);
                    const size_type y_next = y_start + direction(1);
                    const size_type curr_pos = x_next * col_len + y_next;

                    if (
                        x_next < 0 ||
                        x_next >= row_len ||
                        y_next < 0 ||
                        y_next >= col_len ||
                        grid(x_next)(y_next) != kFLOOR ||
                        valids(curr_pos)) {
                        continue;
                    }

                    valids(curr_pos) = true;
                    start_q.push(curr_pos);
                }
            }
        }

        grid(box / col_len)(box % col_len) = kFLOOR;
        return false;
    }
};

References

c++ – LeetCode 928: Minimize Malware Spread II

I’m posting my code for a LeetCode problem. If you’d like to review, please do so. Thank you for your time!

Problem

(This problem is the same as Minimize Malware Spread, with the differences bolded.)

In a network of nodes, each node i is directly connected to another node j if and only if graph(i)(j) = 1.

Some nodes initial are initially infected by malware. Whenever two nodes are directly connected and at least one of those two nodes is infected by malware, both nodes will be infected by malware. This spread of malware will continue until no more nodes can be infected in this manner.

Suppose M(initial) is the final number of nodes infected with malware in the entire network, after the spread of malware stops.

We will remove one node from the initial list, completely removing it and any connections from this node to any other node. Return the node that if removed, would minimize M(initial). If multiple nodes could be removed to minimize M(initial), return such a node with the smallest index.

Example 1:

  • Input: graph = ((1,1,0),(1,1,0),(0,0,1)), initial = (0,1)
  • Output: 0

Example 2:

  • Input: graph = ((1,1,0),(1,1,1),(0,1,1)), initial = (0,1)
  • Output: 1

Example 3:

  • Input: graph = ((1,1,0,0),(1,1,1,0),(0,1,1,1),(0,0,1,1)), initial = (0,1)
  • Output: 1

Note:

  • $1 < text{graph}.text{length} = text{graph}(0).text{length} <= 300$
  • $0 <= text{graph}(i)(j) == text{graph}(j)(i) <= 1$
  • $text{graph}(i)(i) = 1$
  • $1 <= text{initial}.text{length} < text{graph}.text{length}$
  • $0 <= text{initial}(i) < text{graph}.text{length}$

Inputs

((1,1,0),(1,1,0),(0,0,1))
(0,1)
((1,1,0),(1,1,1),(0,1,1))
(0,1)
((1,1,0,0),(1,1,1,0),(0,1,1,1),(0,0,1,1))
(0,1)

Outputs

0
1
1

Code

#include <cstdint>
#include <vector>
#include <queue>
#include <unordered_set>
#include <algorithm>


struct Solution {
    using uint16 = std::uint_fast16_t;
    int minMalwareSpread(
        std::vector<std::vector<int>>& graph,
        std::vector<int>& initial
    ) {
        uint16 smallest_node = 0;
        uint16 initial_len = std::size(initial);
        uint16 min_len = std::size(graph);
        std::sort(std::begin(initial), std::end(initial));

        for (const auto init_node : initial) {
            const uint16 curr_len = breadthFirstSearch(graph, initial, init_node);

            if (curr_len < min_len) {
                min_len = curr_len;
                smallest_node = init_node;
            }
        }

        return smallest_node;
    }

private:
    static uint16 breadthFirstSearch(
        const std::vector<std::vector<int>>& graph,
        std::vector<int>& initial,
        uint16 node
    ) {
        std::queue<uint16> nodes_queue;
        std::unordered_set<uint16> nodes_set = {node};
        uint16 count = 0;

        for (const auto init_node : initial) {
            if (init_node != node) {
                nodes_queue.push(init_node);
            }
        }

        while (!nodes_queue.empty()) {
            uint16 curr_node = nodes_queue.front();
            nodes_queue.pop();

            if (nodes_set.count(curr_node)) {
                continue;
            }

            nodes_set.insert(curr_node);
            ++count;

            for (uint16 index = 0; index < std::size(graph); ++index) {
                if (index != curr_node && graph(curr_node)(index)) {
                    nodes_queue.push(index);
                }
            }
        }

        return count;
    }
};

References

c++ – LeetCode 1453: Maximum Number of Darts Inside of a Circular Dartboard

I’m posting my code for a LeetCode problem. If you’d like to review, please do so. Thank you for your time!

Problem

You have a very large square wall and a circular dartboard placed on the wall. You have been challenged to throw darts into the board blindfolded. Darts thrown at the wall are represented as an array of points on a 2D plane.

Return the maximum number of points that are within or lie on any circular dartboard of radius r.

Example 1:

enter image description here

Input: points = ((-2,0),(2,0),(0,2),(0,-2)), r = 2
Output: 4
Explanation: Circle dartboard with center in (0,0) and radius = 2 contain all points.

Example 2:

enter image description here

Input: points = ((-3,0),(3,0),(2,6),(5,4),(0,9),(7,8)), r = 5
Output: 5
Explanation: Circle dartboard with center in (0,4) and radius = 5 contain all points except the point (7,8).

Example 3:

Input: points = ((-2,0),(2,0),(0,2),(0,-2)), r = 1
Output: 1

Example 4:

Input: points = ((1,2),(3,5),(1,-1),(2,3),(4,1),(1,3)), r = 2
Output: 4

Constraints:

  • $1 <= points.length <= 100$
  • $points(i).length == 2$
  • $-10^4 <= points(i)(0), points(i)(1) <= 10^4$
  • $1 <= r <= 5000$

Inputs

((-2,0),(2,0),(0,2),(0,-2))
2

((-3,0),(3,0),(2,6),(5,4),(0,9),(7,8))
5

((-2,0),(2,0),(0,2),(0,-2))
1

((1,2),(3,5),(1,-1),(2,3),(4,1),(1,3))
2

((5738,-1857),(2264,1769),(5944,-9368),(3459,-9748),(8624,159),(985,-5051),(-8275,-9383),(7923,-591),(-8121,4781),(-9594,938),(-24,223),(9084,-4952),(-6787,5289),(4879,-4),(3998,369),(-7996,-7220),(-414,3638),(5092,4406),(1454,2965),(9210,-6966),(-4111,-8614),(4507,2213),(-4112,3699),(-9956,-2420),(7246,6775),(1164,5762),(6778,-5099),(-6655,-9514),(-2778,-7768),(6973,-7458),(7334,-1124),(4840,-8991),(941,5018),(1937,3608),(6807,6159),(763,1355),(-9776,-5074),(1107,1822),(-6779,-5400),(4219,-5674),(9823,-4630),(-9172,-7089),(-1875,162),(2267,1685),(4161,-1638),(-2475,9697),(-5367,-952),(-7786,4367),(839,1415),(8832,-4596),(-3843,7126),(-4242,8513),(-7883,1951),(9105,8342),(-4109,-4510),(1875,3149),(-7759,-6505),(1764,1624),(-6917,-6653),(-1438,6916),(-758,-3300),(3694,6699),(6135,2622),(7485,8284),(-9616,-8501),(408,4743),(8939,-731),(9208,-3748),(6059,-2587),(8403,4154),(2361,5708),(-3958,-3943),(-1746,-9082),(2864,-3231),(-4940,8519),(-8786,7898),(5154,-3647),(9011,8170),(-205,8717),(...
4411

Outputs

4
5
1
4
23

Code

#include <cstdint>
#include <cmath>
#include <vector>
#include <utility>
#include <algorithm>

class Solution {
    static constexpr double precision = 1e-6;
    double R;

    static struct Point {
        double x;
        double y;
    };

    std::vector<Point> point;

public:
    std::int_fast32_t numPoints(
        const std::vector<std::vector<int>>& points,
        const std::int_fast32_t r
    ) {
    
        const std::size_t length = points.size();
        R = (double) r;
        point.resize(length);

        for (std::size_t len = 0; len < length; ++len) {
            point(len).x = points(len)(0);
            point(len).y = points(len)(1);
        }

        std::int_fast32_t max_darts = 1;

        for (std::size_t i = 0; i < length; ++i) {
            for (std::size_t j = 0; j < length; ++j) {
                if (i == j || getEuclideanDistance(point(i), point(j)) - 2 * R > precision) {
                    continue;
                }

                std::int_fast32_t curr_darts = 0;
                const auto center = getDartboardCenter(point(i), point(j));

                for (std::size_t k = 0; k < length; ++k) {
                    if (getEuclideanDistance(point(k), center.first) - R < precision) {
                        ++curr_darts;
                    }
                }

                max_darts = std::max(max_darts, curr_darts);
            }
        }

        return max_darts;
    }

private:
    double getEuclideanDistance(
        const Point& a,
        const Point& b
    ) {
        return std::sqrt(std::pow(a.x - b.x, 2) + std::pow(a.y - b.y, 2));
    }

    std::pair<Point, Point> getDartboardCenter(
        const Point& a,
        const Point& b
    ) {
        Point mid;
        std::pair<Point, Point> center;
        mid.x = (a.x + b.x) / 2;
        mid.y = (a.y + b.y) / 2;
        const double theta = std::atan2(a.y - b.y, b.x - a.x);
        const double temp_point = getEuclideanDistance(a, b) / 2;
        const double euc_dist = std::sqrt(std::pow(R, 2) - std::pow(temp_point, 2));
        center.first.x = mid.x - euc_dist * std::sin(theta);
        center.first.y = mid.y - euc_dist * std::cos(theta);
        // For optimization, later!
        center.second.x = mid.x + euc_dist * std::sin(theta);
        center.second.y = mid.y + euc_dist * std::cos(theta);
        return center;
    }
};

References

c++ – LeetCode 906: Super Palindromes

I’m posting my code for a LeetCode problem. If you’d like to review, please do so. Thank you for your time!

Problem

Let’s say a positive integer is a superpalindrome if it is a
palindrome, and it is also the square of a palindrome.

Now, given two positive integers L and R (represented as strings),
return the number of superpalindromes in the inclusive range (L, R).

Example 1:

  • Input: L = “4”, R = “1000”
  • Output: 4
  • Explanation: 4, 9, 121, and 484 are superpalindromes.
  • Note that 676 is not a superpalindrome: 26 * 26 = 676, but 26 is not a palindrome.

Note:

  • $1 <= len(L) <= 18$
  • $1 <= len(R) <= 18$
  • L and R are strings representing integers in the range (1, 10^18).
  • int(L) <= int(R)

Inputs

"4"
"1000"

"10"
"99999199999"

"1"
"999999999999999999"

Outputs

4
23
70

Code

#include <cstdint>
#include <cmath>
#include <string>
#include <math.h>
#include <queue>
#include <utility>

struct Solution {
    static std::int_fast32_t superpalindromesInRange(const std::string L, const std::string R) {
        const long double lo_bound = sqrtl(stol(L));
        const long double hi_bound = sqrtl(stol(R));
        std::int_fast32_t superpalindromes = lo_bound <= 3 && 3 <= hi_bound;
        std::queue<std::pair<long, std::int_fast32_t>> queue;
        queue.push({1, 1});
        queue.push({2, 1});

        while (true) {
            const auto curr = queue.front();
            const long num = curr.first;
            const std::int_fast32_t length = curr.second;
            queue.pop();

            if (num > hi_bound) {
                break;
            }

            long W = powl(10, -~length / 2);

            if (num >= lo_bound) {
                superpalindromes += is_palindrome(num * num);
            }

            const long right = num % W;
            const long left = num - (length & 1 ? num % (W / 10) : right);

            if (length & 1) {
                queue.push({10 * left + right, -~length});

            } else {
                for (std::int_fast8_t d = 0; d < 3; ++d) {
                    queue.push({10 * left + d * W + right, -~length});
                }
            }
        }

        return superpalindromes;
    }

private:
    static bool is_palindrome(const long num) {
        if (!num) {
            return true;
        }

        if (!num % 10) {
            return false;
        }

        long left = num;
        long right = 0;

        while (left >= right) {
            if (left == right || left / 10 == right) {
                return true;
            }

            right = 10 * right + (left % 10);
            left /= 10;
        }

        return false;
    }

};

References

c++ – LeetCode 913: Cat and Mouse

I’m posting my code for a LeetCode problem. If you’d like to review, please do so. Thank you for your time!

Problem

A game on an undirected graph is played by two players, Mouse and Cat,
who alternate turns.

The graph is given as follows: graph(a) is a list of all nodes b such
that ab is an edge of the graph.

Mouse starts at node 1 and goes first, Cat starts at node 2 and goes
second, and there is a Hole at node 0.

During each player’s turn, they must travel along one edge of the
graph that meets where they are. For example, if the Mouse is at node
1, it must travel to any node in graph(1).

Additionally, it is not allowed for the Cat to travel to the Hole
(node 0.)

Then, the game can end in 3 ways:

  • If ever the Cat occupies the same node as the Mouse, the Cat wins.
  • If ever the Mouse reaches the Hole, the Mouse wins.
  • If ever a position is repeated (ie. the players are in the same position as a previous turn, and it is the same player’s turn to
    move), the game is a draw.

Given a graph, and assuming both players play optimally, return 1 if
the game is won by Mouse, 2 if the game is won by Cat, and 0 if the
game is a draw.

Inputs

((2,5),(3),(0,4,5),(1,4,5),(2,3),(0,2,3))
((1,3),(0),(3),(0,2))
((2,3),(3,4),(0,4),(0,1),(1,2))
((2,5),(3),(0,4,5),(1,4,5),(2,3),(0,2,3),(2,3),(3,4),(0,4),(0,1),(1,2))
((2,5),(3),(0,4,5),(1,4,5),(2,3),(0,2,3),(2,3),(3,4),(0,4),(0,1),(1,2),(6,4,3),(6,4,2),(1,4,3),(2,4,3))

Outputs

0
1
1
2
2

Code

#include <vector>
#include <queue>

class Solution {

    static constexpr int mouse_turn = 0;
    static constexpr int cat_turn = 1;
    static constexpr int draw = 0;
    static constexpr int mouse_wins = 1;
    static constexpr int cat_wins = 2;

public:
    static const int catMouseGame(const std::vector<std::vector<int>> &graph) {
        const int size = graph.size();
        std::vector<std::vector<std::vector<int>>> states(
            size,
            std::vector<std::vector<int>>(size, std::vector<int>(2, draw))
        );

        std::vector<std::vector<std::vector<int>>> indegree_paths(
            size,
            std::vector<std::vector<int>>(size, std::vector<int>(2))
        );

        std::queue<std::vector<int>> queue;

        for (int i_ind = 0; i_ind < size; i_ind++) {
            if (i_ind) {
                states(0)(i_ind)(mouse_turn) = states(0)(i_ind)(cat_turn) = mouse_wins;
                queue.push(std::vector<int> {0, i_ind, mouse_turn, mouse_wins});
                queue.push(std::vector<int> {0, i_ind, cat_turn, mouse_wins});
                states(i_ind)(i_ind)(mouse_turn) = states(i_ind)(i_ind)(cat_turn) = cat_wins;
                queue.push(std::vector<int> {i_ind, i_ind, mouse_turn, cat_wins});
                queue.push(std::vector<int> {i_ind, i_ind, cat_turn, cat_wins});
            }

            for (int j_ind = 0; j_ind < size; j_ind++) {
                indegree_paths(i_ind)(j_ind)(mouse_turn) = graph(i_ind).size();
                indegree_paths(i_ind)(j_ind)(cat_turn) = graph(j_ind).size();

                if (find(graph(j_ind).begin(), graph(j_ind).end(), 0) != graph(j_ind).end()) {
                    indegree_paths(i_ind)(j_ind)(cat_turn)--;
                }
            }
        }

        while (!queue.empty()) {
            const int mouse_state = queue.front()(0);
            const int cat_state = queue.front()(1);
            const int turn = queue.front()(2);
            const int final_state = queue.front()(3);
            queue.pop();
            const int prev_turn = not turn;

            if (mouse_turn == prev_turn) {
                for (const auto &mouse : graph(mouse_state)) {
                    if (states(mouse)(cat_state)(prev_turn) == draw) {
                        if (mouse_wins == final_state) {
                            states(mouse)(cat_state)(prev_turn) = mouse_wins;

                        } else {
                            indegree_paths(mouse)(cat_state)(prev_turn)--;

                            if (not indegree_paths(mouse)(cat_state)(prev_turn)) {
                                states(mouse)(cat_state)(prev_turn) = cat_wins;
                            }
                        }

                        if (states(mouse)(cat_state)(prev_turn) != draw) {
                            queue.push(
                                std::vector<int> {mouse, cat_state, prev_turn, states(mouse)(cat_state)(prev_turn)}
                            );
                        }
                    }
                }

            } else {
                for (const auto &cat : graph(cat_state)) {
                    if (not cat) {
                        continue;
                    }

                    if (states(mouse_state)(cat)(prev_turn) == draw) {
                        if (cat_wins == final_state) {
                            states(mouse_state)(cat)(prev_turn) = cat_wins;

                        } else {
                            indegree_paths(mouse_state)(cat)(prev_turn)--;

                            if (not indegree_paths(mouse_state)(cat)(prev_turn)) {
                                states(mouse_state)(cat)(prev_turn) = mouse_wins;
                            }
                        }


                        if (states(mouse_state)(cat)(prev_turn) != draw) {
                            queue.push(
                                std::vector<int> {mouse_state, cat, prev_turn, states(mouse_state)(cat)(prev_turn)}
                            );
                        }
                    }
                }
            }
        }

        return states(1)(2)(mouse_turn);
    }

};

References

c++ – LeetCode 126: Word Ladder II

I’m posting my code for a LeetCode problem copied here. If you would like to review, please do so. Thank you for your time!

Problem

Given two words (begin and end), and a dictionary’s word list,
find all shortest transformation sequence(s) from begin to end,
such that:

Only one letter can be changed at a time.

Each transformed word must exist in the word list. Note that begin
is not a transformed word. Note:

  • Return an empty list if there is no such transformation sequence.
  • All words have the same length.
  • All words contain only lowercase alphabetic characters.
  • You may assume no duplicates in the word list.
  • You may assume begin and end are non-empty and are not the same.

Inputs

"hit"
"cog"
("hot","dot","dog","lot","log","cog")
"hit"
"cog"
("hot","dot","dog","lot","log")

Outputs

(("hit","hot","dot","dog","cog"),("hit","hot","lot","log","cog"))
()

Code

#include <vector>
#include <string>
#include <unordered_set>
#include <unordered_map>
#include <algorithm>

struct Solution {
    const inline std::vector<std::vector<std::string>> findLadders(
                const std::string begin,
                const std::string end,
                const std::vector<std::string> &words
    ) {
        std::unordered_set<std::string> dict_words(words.begin(), words.end());

        if (dict_words.find(end) == dict_words.end()) {
            return {};
        }

        graph graph;
        std::vector<std::vector<std::string>> paths;
        std::vector<std::string> path = {begin};

        if (make_graph(graph, begin, end, dict_words)) {
            find_paths(graph, begin, end, path, paths);
        }

        return paths;
    }

private:

    typedef unordered_map<std::string, std::vector<std::string>> graph;

    const inline bool make_graph(
        graph &graph,
        const std::string begin,
        const std::string end,
        std::unordered_set<std::string> &dict_words
    ) {
        std::unordered_set<std::string> candidate_words;
        candidate_words.insert(begin);

        while (!candidate_words.empty()) {
            if (candidate_words.find(end) != candidate_words.end()) {
                return true;
            }

            for (std::string word : candidate_words) {
                dict_words.erase(word);
            }

            std::unordered_set<std::string> curr_word;

            for (std::string word : candidate_words) {
                std::string parent = word;

                for (int chari = 0; chari < word.size(); chari++) {
                    char character = word(chari);

                    for (int letter = 0; letter < 26; letter++) {
                        word(chari) = 'a' + letter;

                        if (dict_words.find(word) != dict_words.end()) {
                            curr_word.insert(word);
                            graph(parent).push_back(word);
                        }
                    }

                    word(chari) = character;
                }
            }

            std::swap(candidate_words, curr_word);
        }

        return false;
    }

    static const inline void find_paths(
        graph &graph,
        const std::string begin,
        const std::string end,
        std::vector<std::string> &path,
        std::vector<std::vector<std::string>> &paths
    ) {
        if (begin == end) {
            paths.push_back(path);

        } else {
            for (std::string child : graph(begin)) {
                path.push_back(child);
                find_paths(graph, child, end, path, paths);
                path.pop_back();
            }
        }
    }
};

References

algorithms – Math behind leetcode problem 47 permutations II

Please tell me why the expression i>0 && nums(i) == nums(i-1) && !used(i-1) works on getting unique permutations. And what is the math behind it?
The problem is as follows:
Given a collection of numbers that might contain duplicates, return all possible unique permutations.
Example:

Input: (1,1,2)
Output:
(
  (1,1,2),
  (1,2,1),
  (2,1,1)
)

Here is the code:

class Solution {
public:
    vector<vector<int>> permuteUnique(vector<int>& nums) {   
        vector<vector<int>> result; 
        vector<int> temp;
        vector<bool> used(nums.size(), false);
        sort(nums.begin(), nums.end());
        backtrack(nums, temp, result, used);
        return result;        
    }
    
    void backtrack(vector<int>& nums, vector<int>& temp, vector<vector<int>>& result, vector<bool>& used){
        
        if(temp.size() == nums.size()){
            result.emplace_back(temp);
        }else{
            
            for(int i=0; i<nums.size(); i++){
                if(used(i) || i>0 && nums(i) == nums(i-1) && !used(i-1)) continue; 
                used(i) = true;
                temp.push_back(nums(i));
                backtrack(nums, temp, result, used);
                used(i) = false;
                temp.pop_back();
            }            
        }        
    }    
};

c++ – LeetCode 1463: Cherry Pickup II

I’m posting my code for a LeetCode problem copied here. If you would like to review, please do so. Thank you for your time!

Problem

Given a rows x cols matrix grid representing a field of cherries.
Each cell in grid represents the number of cherries that you can
collect.

You have two robots that can collect cherries for you, Robot #1 is
located at the top-left corner (0,0), and Robot #2 is located at the
top-right corner (0, cols-1) of the grid.

Return the maximum number of cherries collection using both robots by
following the rules below:

  • From a cell (i,j), robots can move to cell (i+1, j-1) , (i+1, j) or (i+1, j+1).
  • When any robot is passing through a cell, It picks it up all cherries, and the cell becomes an empty cell (0).
  • When both robots stay on the same cell, only one of them takes the cherries.
  • Both robots cannot move outside of the grid at any moment.
  • Both robots should reach the bottom row in the grid.

Example 1:

enter image description here

Input: grid = ((3,1,1),(2,5,1),(1,5,5),(2,1,1))
Output: 24

Explanation: Path of robot #1 and #2 are described in color green and
blue respectively.
Cherries taken by Robot #1, $(3 + 2 + 5 + 2) =
> 12$
.
Cherries taken by Robot #2, $(1 + 5 + 5 + 1) = 12$.
Total of cherries: $12 + 12 = 24$.

Example 2:

enter image description here

Input: grid = ((1,0,0,0,0,0,1),(2,0,0,0,0,3,0),(2,0,9,0,0,0,0),(0,3,0,5,4,0,0),(1,0,2,3,0,0,6))

Output: 28

Explanation: Path of robot #1 and #2 are described in
color green and blue respectively.
Cherries taken by Robot #1,
$(1 + 9 + 5 + 2) = 17$.

Cherries taken by Robot #2, $(1 + 3 + 4
> + 3) = 11$
.

Total of cherries: $17 + 11 = 28$.

Constraints:

  • $rows == grid.length$
  • $cols == grid(i).length$
  • $2 <= rows, cols <= 70$
  • $0 <= grid(i)(j) <= 100 $

Inputs

((3,1,1),(2,5,1),(1,5,5),(2,1,1))
((1,0,0,3),(0,0,0,3),(0,0,3,3),(9,0,3,3))
((1,10,0,3,86,40),(0,0,0,3,86,40),(0,0,3,3,86,40),(9,0,3,3,86,40), (1,0,40,3,86,40),(0,22,0,3,86,40),(99,0,3,3,86,40),(9,0,3,3,86,40))

Outputs

24
22
819

Code

#include <vector>
#include <cstring>

struct Solution {
    int map_cherries(70)(70)(70) = {};

    inline int cherryPickup(std::vector<std::vector<int>> &grid) {
        std::memset(map_cherries, -1, sizeof(map_cherries));
        const int row_length = grid.size();
        const int col_length = grid(0).size();
        return depth_first_search(grid, row_length, col_length, 0, 0, col_length - 1);
    }

private:
    const inline int depth_first_search(
        std::vector<std::vector<int>> &grid,
        const int row_length,
        const int col_length,
        int row,
        int left_robot,
        int right_robot
    ) {
        if (row == row_length) {
            return 0;
        }

        if (map_cherries(row)(left_robot)(right_robot) != -1) {
            return map_cherries(row)(left_robot)(right_robot);
        }

        int max_cherries = 0;

        for (int left = -1; left < 2; left++) {
            for (int right = -1; right < 2; right++) {
                const int curr_left_robot = left_robot + left;
                const int curr_right_robot = right_robot + right;

                if (curr_left_robot > -1 and curr_left_robot < col_length and curr_right_robot > -1 and curr_right_robot < col_length) {
                    max_cherries = std::max(max_cherries, depth_first_search(
                                                grid,
                                                row_length,
                                                col_length,
                                                row + 1,
                                                curr_left_robot,
                                                curr_right_robot
                                            ));
                }
            }
        }

        int cherries = grid(row)(left_robot);

        if (left_robot != right_robot) {
            cherries += grid(row)(right_robot);
        }

        return map_cherries(row)(left_robot)(right_robot) = max_cherries + cherries;
    }
};

References