Sunday, November 17, 2024
Google search engine
HomeLanguagesDynamic ProgrammingNumber of palindromic paths in a matrix

Number of palindromic paths in a matrix

Given a matrix containing lower alphabetical characters only, we need to count number of palindromic paths in given matrix. A path is defined as a sequence of cells starting from top-left cell and ending at bottom-right cell. We are allowed to move to right and down only from current cell. 

Examples: 

Input : mat[][] = {"aaab”, 
                   "baaa”
                   “abba”}
Output : 3

Number of palindromic paths are 3 from top-left to 
bottom-right.
aaaaaa (0, 0) -> (0, 1) -> (1, 1) -> (1, 2) -> 
                                (1, 3) -> (2, 3)    
aaaaaa (0, 0) -> (0, 1) -> (0, 2) -> (1, 2) -> 
                                (1, 3) -> (2, 3)    
abaaba (0, 0) -> (1, 0) -> (1, 1) -> (1, 2) -> 
                                 (2, 2) -> (2, 3)    

palindrome-matrix

We can solve this problem recursively, we start from two corners of a palindromic path(top-left and bottom right). In each recursive call, we maintain a state which will constitute two cells one from starting and one from end which should be equal for palindrome property. If at a state, both cell characters are equal then we call recursively with all possible movements in both directions. 

As this can lead to solving same subproblem multiple times, we have taken a map memo in below code which stores the calculated result with key as indices of starting and ending cell so if subproblem with same starting and ending cell is called again, result will be returned by memo directly instead of recalculating again.

Implementation:

CPP




// C++ program to get number of palindrome
// paths in matrix
#include <bits/stdc++.h>
 
using namespace std;
 
#define R 3
#define C 4
 
// struct to represent state of recursion
// and key of map
struct cells
{
    //  indices of front cell
    int rs, cs;
 
    //  indices of end cell
    int re, ce;
    cells(int rs, int cs, int re, int ce)
        : rs(rs)
        , cs(cs)
        , re(re)
        , ce(ce)
    {
    }
 
    // operator overloading to compare two
    // cells which rs needed for map
    bool operator<(const cells& other) const
    {
        return ((rs != other.rs) || (cs != other.cs)
                || (re != other.re) || (ce != other.ce));
    }
};
 
// recursive method to return number
//  of palindromic paths in matrix
// (rs, cs) ==> Indices of current cell
//              from a starting point (First Row)
// (re, ce) ==> Indices of current cell
//              from a ending point (Last Row)
// memo     ==> To store results of
//              already computed problems
int getPalindromicPathsRecur(char mat[R][C],
                             int rs, int cs,
                             int re, int ce,
                             map<cells, int>& memo)
{
    // Base Case 1 : if any index rs out of boundary,
    // return 0
    if (rs < 0 || rs >= R || cs < 0 || cs >= C)
        return 0;
    if (re < 0 || re < rs || ce < 0 || ce < cs)
        return 0;
 
    // Base case 2 : if values are not equal
    // then palindrome property rs not satisfied,
    // so return 0
    if (mat[rs][cs] != mat[re][ce])
        return 0;
 
    // If we reach here, then matrix cells are same.
 
    // Base Case 3 : if indices are adjacent then
    // return 1
    if (abs((rs - re) + (cs - ce)) <= 1)
        return 1;
 
    //  if result rs precalculated, return from map
    if (memo.find(cells(rs, cs, re, ce))
        != memo.end())
        return memo[cells(rs, cs, re, ce)];
 
    int ret = 0; // Initialize result
 
    // calling recursively for all possible movements
    ret += getPalindromicPathsRecur(mat, rs + 1,
                                    cs, re - 1,
                                    ce, memo);
    ret += getPalindromicPathsRecur(mat, rs + 1,
                                    cs, re,
                                    ce - 1, memo);
    ret += getPalindromicPathsRecur(mat, rs,
                                    cs + 1, re - 1,
                                    ce, memo);
    ret += getPalindromicPathsRecur(mat, rs,
                                    cs + 1, re,
                                    ce - 1, memo);
 
    // storing the calculated result in map
    memo[cells(rs, cs, re, ce)] = ret;
 
    return ret;
}
 
//  method returns number of palindromic paths in matrix
int getPalindromicPaths(char mat[R][C])
{
    map<cells, int> memo;
    return getPalindromicPathsRecur(mat, 0, 0, R - 1, C - 1,
                                    memo);
}
 
//  Driver code
int main()
{
    char mat[R][C] = { 'a', 'a', 'a',
                      'b', 'b', 'a',
                       'a', 'a', 'a',
                      'b', 'b', 'a' };
    printf("%d", getPalindromicPaths(mat));
 
    return 0;
}


Java




// Java program to get number of palindrome paths in matrix
import java.util.HashMap;
 
// Cells class definition
class Cells {
  int rs;
  int cs;
  int re;
  int ce;
 
  // Constructor
  public Cells(int rs, int cs, int re, int ce)
  {
    this.rs = rs;
    this.cs = cs;
    this.re = re;
    this.ce = ce;
  }
 
  // Equals method to compare two Cells objects
  @Override public boolean equals(Object o)
  {
    if (o instanceof Cells) {
      Cells other = (Cells)o;
      return (rs == other.rs) && (cs == other.cs)
        && (re == other.re) && (ce == other.ce);
    }
    return false;
  }
 
  // hashCode() function to calculate hash
  @Override public int hashCode()
  {
    return (rs * 100 + cs) * 100 + (re * 100 + ce);
  }
}
 
class PalindromicPaths {
  // Rows and Columns in the matrix
  static int R = 3;
  static int C = 4;
 
  //  method to return number of palindromic paths in
  //  matrix
  static int getPalindromicPaths(char[][] mat)
  {
    HashMap<Cells, Integer> memo = new HashMap<>();
    R = mat.length;
    C = mat[0].length;
    return getPalindromicPathsRecur(mat, 0, 0, R - 1,
                                    C - 1, memo);
  }
 
  // recursive method to return number of palindromic
  // paths in matrix
  static int
    getPalindromicPathsRecur(char[][] mat, int rs, int cs,
                             int re, int ce,
                             HashMap<Cells, Integer> memo)
  {
    // Base Case 1 : if any index is out of boundary,
    // return 0
    if (rs < 0 || rs >= R || cs < 0 || cs >= C) {
      return 0;
    }
    if (re < 0 || re < rs || ce < 0 || ce < cs) {
      return 0;
    }
 
    // Base case 2 : if values are not equal then
    // palindrome property is not satisfied, so return 0
    if (mat[rs][cs] != mat[re][ce]) {
      return 0;
    }
 
    // If we reach here, then matrix cells are same.
 
    // Base Case 3 : if indices are adjacent then return
    // 1
    if (Math.abs((rs - re) + (cs - ce)) <= 1) {
      return 1;
    }
 
    Cells key = new Cells(rs, cs, re, ce);
    //  if result is precalculated, return from map
    if (memo.containsKey(key)) {
      return memo.get(key);
    }
 
    int ret = 0; // Initialize result
 
    // calling recursively for all possible movements
    ret += getPalindromicPathsRecur(mat, rs + 1, cs,
                                    re - 1, ce, memo);
    ret += getPalindromicPathsRecur(mat, rs + 1, cs, re,
                                    ce - 1, memo);
    ret += getPalindromicPathsRecur(mat, rs, cs + 1,
                                    re - 1, ce, memo);
    ret += getPalindromicPathsRecur(
      mat, rs, cs + 1, re - 1, ce - 1, memo);
 
    // storing the calculated result in map
    memo.put(key, ret);
 
    return ret;
  }
 
  // Driver code
  public static void main(String[] args)
  {
    char[][] mat = { { 'a', 'a', 'a' },
                    { 'b', 'b', 'a' },
                    { 'a', 'a', 'a' },
                    { 'b', 'b', 'a' } };
    System.out.println(getPalindromicPaths(mat));
  }
}
 
// This code is contributed by phasing17.


Python3




# Python3 program to get number of palindrome
# paths in matrix
R = 3
C = 4
 
# struct to represent state of recursion
# and key of map
class Cells:
    def __init__(self, rs, cs, re, ce):
        self.rs = rs
        self.cs = cs
        self.re = re
        self.ce = ce
    def __eq__(self, other):
        if other:
            return (self.rs, self.cs, self.re, self.ce) == (other.rs, other.cs, other.re, other.ce)
        return False
         
    def __hash__(self):
        return hash((self.rs, self.cs, self.re, self.ce))
 
# recursive method to return number
#  of palindromic paths in matrix
# (rs, cs) ==> Indices of current cell
#              from a starting point (First Row)
# (re, ce) ==> Indices of current cell
#              from a ending point (Last Row)
# memo     ==> To store results of
#              already computed problems
def getPalindromicPathsRecur(mat, rs, cs, re, ce, memo):
     
    # Base Case 1 : if any index rs out of boundary,
    # return 0
    if rs < 0 or rs >= R or cs < 0 or cs >= C:
        return 0
    if re < 0 or re < rs or ce < 0 or ce < cs:
        return 0
 
    # Base case 2 : if values are not equal
    # then palindrome property rs not satisfied,
    # so return 0
    if mat[rs][cs] != mat[re][ce]:
        return 0
 
    # If we reach here, then matrix cells are same.
 
    # Base Case 3 : if indices are adjacent then
    # return 1
    if abs((rs - re) + (cs - ce)) <= 1:
        return 1
 
    key = Cells(rs, cs, re, ce)
    #  if result rs precalculated, return from map
    if key in memo:
        return memo[key]
 
    ret = 0  # Initialize result
 
    # calling recursively for all possible movements
    ret += getPalindromicPathsRecur(mat, rs + 1, cs, re - 1, ce, memo)
    ret += getPalindromicPathsRecur(mat, rs + 1, cs, re, ce - 1, memo)
    ret += getPalindromicPathsRecur(mat, rs, cs + 1, re - 1, ce, memo)
    ret += getPalindromicPathsRecur(mat, rs, cs + 1, re - 1, ce - 1, memo)
 
    # storing the calculated result in map
    memo[key] = ret
 
    return ret
 
#  method returns number of palindromic paths in matrix
def getPalindromicPaths(mat):
    memo = {}
    R = len(mat)
    C = len(mat[0])
    res = getPalindromicPathsRecur(mat, 0, 0, R - 1, C - 1, memo)
    return res
 
#  Driver code
if __name__ == "__main__":
    mat = [['a', 'a', 'a'],
           ['b', 'b', 'a'],
           ['a', 'a', 'a'],
           ['b', 'b', 'a']]
    print(getPalindromicPaths(mat))
     
# This code is contributed by phasing17.


C#




// C# program to get number of palindrome paths in matrix
using System;
using System.Collections.Generic;
 
// Cells class definition
class Cells {
  int rs;
  int cs;
  int re;
  int ce;
 
  // Constructor
  public Cells(int rs, int cs, int re, int ce)
  {
    this.rs = rs;
    this.cs = cs;
    this.re = re;
    this.ce = ce;
  }
 
  // Equals method to compare two Cells objects
  public override bool Equals(Object o)
  {
    if (o is Cells) {
      Cells other = (Cells)o;
      return (rs == other.rs) && (cs == other.cs)
        && (re == other.re) && (ce == other.ce);
    }
    return false;
  }
 
  // hashCode() function to calculate hash
  public override int GetHashCode()
  {
    return (rs * 100 + cs) * 100 + (re * 100 + ce);
  }
}
 
class PalindromicPaths {
  // Rows and Columns in the matrix
  static int R = 3;
  static int C = 4;
 
  //  method to return number of palindromic paths in
  //  matrix
  static int GetPalindromicPaths(char[][] mat)
  {
    Dictionary<Cells, int> memo
      = new Dictionary<Cells, int>();
    R = mat.Length;
    C = mat[0].Length;
    return GetPalindromicPathsRecur(mat, 0, 0, R - 1,
                                    C - 1, memo);
  }
 
  // recursive method to return number of palindromic
  // paths in matrix
  static int
    GetPalindromicPathsRecur(char[][] mat, int rs, int cs,
                             int re, int ce,
                             Dictionary<Cells, int> memo)
  {
    // Base Case 1 : if any index is out of boundary,
    // return 0
    if (rs < 0 || rs >= R || cs < 0 || cs >= C) {
      return 0;
    }
    if (re < 0 || re < rs || ce < 0 || ce < cs) {
      return 0;
    }
 
    // Base case 2 : if values are not equal then
    // palindrome property is not satisfied, so return 0
    if (mat[rs][cs] != mat[re][ce]) {
      return 0;
    }
 
    // If we reach here, then matrix cells are same.
 
    // Base Case 3 : if indices are adjacent then return
    // 1
    if (Math.Abs((rs - re) + (cs - ce)) <= 1) {
      return 1;
    }
 
    Cells key = new Cells(rs, cs, re, ce);
    //  if result is precalculated, return from map
    if (memo.ContainsKey(key)) {
      return memo[key];
    }
 
    int ret = 0; // Initialize result
 
    // calling recursively for all possible movements
    ret += GetPalindromicPathsRecur(mat, rs + 1, cs,
                                    re - 1, ce, memo);
    ret += GetPalindromicPathsRecur(mat, rs + 1, cs, re,
                                    ce - 1, memo);
    ret += GetPalindromicPathsRecur(mat, rs, cs + 1,
                                    re - 1, ce, memo);
    ret += GetPalindromicPathsRecur(
      mat, rs, cs + 1, re - 1, ce - 1, memo);
 
    // storing the calculated result in map
    memo[key] = ret;
 
    return ret;
  }
 
  // Driver code
  public static void Main(string[] args)
  {
    char[][] mat = { new char[] { 'a', 'a', 'a' },
                    new char[] { 'b', 'b', 'a' },
                    new char[] { 'a', 'a', 'a' },
                    new char[] { 'b', 'b', 'a' } };
    Console.WriteLine(GetPalindromicPaths(mat));
  }
}
 
// This code is contributed by phasing17.


Javascript




// JavaScript code to get number of palindrome paths in matrix
const R = 3;
const C = 4;
 
// class to represent state of recursion
// and key of map
class Cells {
  constructor(rs, cs, re, ce) {
    this.rs = rs;
    this.cs = cs;
    this.re = re;
    this.ce = ce;
  }
 
  // custom equality check
  equals(other) {
    if (other) {
      return (
        this.rs === other.rs &&
        this.cs === other.cs &&
        this.re === other.re &&
        this.ce === other.ce
      );
    }
    return false;
  }
}
 
// map to store results of already computed problems
const memo = new Map();
 
// recursive method to return number of palindromic paths in matrix
// (rs, cs) ==> Indices of current cell from a starting point (First Row)
// (re, ce) ==> Indices of current cell from a ending point (Last Row)
function getPalindromicPathsRecur(mat, rs, cs, re, ce) {
  // Base Case 1 : if any index rs out of boundary, return 0
  if (rs < 0 || rs >= R || cs < 0 || cs >= C) {
    return 0;
  }
  if (re < 0 || re < rs || ce < 0 || ce < cs) {
    return 0;
  }
 
  // Base case 2 : if values are not equal then palindrome property rs not satisfied, so return 0
  if (mat[rs][cs] !== mat[re][ce]) {
    return 0;
  }
 
  // If we reach here, then matrix cells are same.
 
  // Base Case 3 : if indices are adjacent then return 1
  if (Math.abs((rs - re) + (cs - ce)) <= 1) {
    return 1;
  }
 
  const key = new Cells(rs, cs, re, ce);
  //  if result rs precalculated, return from map
  if (memo.has(key)) {
    return memo.get(key);
  }
 
  let ret = 0; // Initialize result
 
  // calling recursively for all possible movements
  ret += getPalindromicPathsRecur(mat, rs + 1, cs, re - 1, ce);
  ret += getPalindromicPathsRecur(mat, rs + 1, cs, re, ce - 1);
  ret += getPalindromicPathsRecur(mat, rs, cs + 1, re - 1, ce);
  ret += getPalindromicPathsRecur(mat, rs, cs + 1, re - 1, ce - 1);
 
  // storing the calculated result in map
  memo.set(key, ret);
 
  return ret;
}
 
//  method returns number of palindromic paths in matrix
function getPalindromicPaths(mat) {
  const R = mat.length;
  const C = mat[0].length;
  const res = getPalindromicPathsRecur(mat, 0, 0, R - 1, C - 1);
  return res;
}
 
//  Driver code
let mat = [['a', 'a', 'a'],
           ['b', 'b', 'a'],
           ['a', 'a', 'a'],
           ['b', 'b', 'a']]
console.log(getPalindromicPaths(mat))
 
// This code is contributed by phasing17.


Output

3

Time Complexity : O((R x C)2)

Space Complexity :  O((R x C)2) due to use of memoization map.

This article is contributed by Utkarsh Trivedi. If you like neveropen and would like to contribute, you can also write an article using write.geeksforgeeks.org or mail your article to review-team@geeksforgeeks.org. See your article appearing on the neveropen main page and help other Geeks. 

Feeling lost in the world of random DSA topics, wasting time without progress? It’s time for a change! Join our DSA course, where we’ll guide you on an exciting journey to master DSA efficiently and on schedule.
Ready to dive in? Explore our Free Demo Content and join our DSA course, trusted by over 100,000 neveropen!

RELATED ARTICLES

Most Popular

Recent Comments