Saturday, December 28, 2024
Google search engine

Temple Offerings

Consider a devotee wishing to give offerings to temples along with a mountain range. The temples are located in a row at different heights. Each temple should receive at least one offer. If two adjacent temples are at different altitudes, then the temple that is higher up should receive more offerings than the one that is lower down. If two adjacent temples are at the same height, then their offerings relative to each other do not matter. Given the number of temples and the heights of the temples in order, find the minimum number of offerings to bring.

Examples:

Input  : 3
         1 2 2
Output : 4
All temples must receive at-least one offering.
Now, the second temple is at a higher altitude
compared to the first one. Thus it receives one
extra offering. 
The second temple and third temple are at the 
same height, so we do not need to modify the 
offerings. Offerings given are therefore: 1, 2,
1 giving a total of 4.

Input  : 6
         1 4 3 6 2 1
Output : 10
We can distribute the offerings in the following
way, 1, 2, 1, 3, 2, 1. The second temple has to 
receive more offerings than the first due to its 
height being higher. The fourth must receive more
than the fifth, which in turn must receive more 
than the sixth. Thus the total becomes 10.
Recommended Practice

We notice that each temple can either be above, below or at the same level as the temple next to it. The offerings required at each temple are equal to the maximum length of the chain of temples at a lower height as shown in the image.

Temples

Naive Approach:
To follow the given rule, a temple must be offered at least x+1 where x is the maximum of the following two.

  1. Number of temples on left in increasing order.
  2. Number of temples on right in increasing order.

A naive method of solving this problem would be for each temple, go to the left until altitude increases, and do the same for the right.

C++




// Program to find minimum total offerings required
#include <iostream>
using namespace std;
 
// Returns minimum offerings required
int offeringNumber(int n, int templeHeight[])
{
    int sum = 0;  // Initialize result
 
    // Go through all temples one by one
    for (int i = 0; i < n; ++i)
    {
        // Go to left while height keeps increasing
        int left = 0, right = 0;
        for (int j = i - 1; j >= 0; --j)
        {
            if (templeHeight[j] < templeHeight[j + 1])
                ++left;
            else
                break;
        }
 
        // Go to right while height keeps increasing
        for (int j = i + 1; j < n; ++j)
        {
            if (templeHeight[j] < templeHeight[j - 1])
                ++right;
            else
                break;
        }
 
        // This temple should offer maximum of two
        // values to follow the rule.
        sum += max(right, left) + 1;
    }
 
    return sum;
}
 
// Driver code
int main()
{
    int arr1[3] = {1, 2, 2};
    cout << offeringNumber(3, arr1) << "\n";
    int arr2[6] = {1, 4, 3, 6, 2, 1};
    cout << offeringNumber(6, arr2) << "\n";
    return 0;
}


Java




// Program to find minimum
// total offerings required
import java.io.*;
 
class GFG
{
     
// Returns minimum
// offerings required
static int offeringNumber(int n,
                          int templeHeight[])
{
    int sum = 0; // Initialize result
 
    // Go through all
    // temples one by one
    for (int i = 0; i < n; ++i)
    {
        // Go to left while
        // height keeps increasing
        int left = 0, right = 0;
        for (int j = i - 1; j >= 0; --j)
        {
            if (templeHeight[j] <
                templeHeight[j + 1])
                ++left;
            else
                break;
        }
 
        // Go to right while
        // height keeps increasing
        for (int j = i + 1; j < n; ++j)
        {
            if (templeHeight[j] <
                templeHeight[j - 1])
                ++right;
            else
                break;
        }
 
        // This temple should offer
        // maximum of two values
        // to follow the rule.
        sum += Math.max(right, left) + 1;
    }
 
    return sum;
}
 
// Driver code
public static void main (String[] args)
{
int arr1[] = {1, 2, 2};
System.out.println(offeringNumber(3, arr1));
int arr2[] = {1, 4, 3,
              6, 2, 1};
System.out.println(offeringNumber(6, arr2));
}
}
 
// This code is contributed by akt_mit


Python3




# Program to find minimum total
# offerings required.
 
# Returns minimum offerings required
def offeringNumber(n, templeHeight):
    sum = 0 # Initialize result
     
    # Go through all temples one by one
    for i in range(n):
         
        # Go to left while height
        # keeps increasing
        left = 0
        right = 0
        for j in range(i - 1, -1, -1):
            if (templeHeight[j] < templeHeight[j + 1]):
                left += 1
            else:
                break
                 
        # Go to right while height
        # keeps increasing
        for j in range(i + 1, n):
            if (templeHeight[j] < templeHeight[j - 1]):
                right += 1
            else:
                break
                 
        # This temple should offer maximum
        # of two values to follow the rule.
        sum += max(right, left) + 1
    return sum
 
# Driver Code
arr1 = [1, 2, 2]
print(offeringNumber(3, arr1))
arr2 = [1, 4, 3, 6, 2, 1]
print(offeringNumber(6, arr2))
 
# This code is contributed
# by sahilshelangia


C#




// Program to find minimum
// total offerings required
using System;
 
class GFG
{
     
// Returns minimum
// offerings required
static int offeringNumber(int n,
                          int []templeHeight)
{
    int sum = 0; // Initialize result
 
    // Go through all
    // temples one by one
    for (int i = 0; i < n; ++i)
    {
        // Go to left while
        // height keeps increasing
        int left = 0, right = 0;
        for (int j = i - 1; j >= 0; --j)
        {
            if (templeHeight[j] <
                templeHeight[j + 1])
                ++left;
            else
                break;
        }
 
        // Go to right while
        // height keeps increasing
        for (int j = i + 1; j < n; ++j)
        {
            if (templeHeight[j] <
                templeHeight[j - 1])
                ++right;
            else
                break;
        }
 
        // This temple should offer
        // maximum of two values
        // to follow the rule.
        sum += Math.Max(right, left) + 1;
    }
 
    return sum;
}
 
// Driver code
static public void Main ()
{
    int []arr1 = {1, 2, 2};
    Console.WriteLine(offeringNumber(3, arr1));
     
    int []arr2 = {1, 4, 3,
                  6, 2, 1};
    Console.WriteLine(offeringNumber(6, arr2));
}
}
 
// This code is contributed by aj_36


PHP




<?php
// Program to find minimum total offerings required
 
// Returns minimum offerings required
function offeringNumber($n, $templeHeight)
{
    $sum = 0; // Initialize result
 
    // Go through all temples one by one
    for ($i = 0; $i < $n; ++$i)
    {
        // Go to left while height keeps increasing
        $left = 0; $right = 0;
        for ($j = $i - 1; $j >= 0; --$j)
        {
            if ($templeHeight[$j] < $templeHeight[$j + 1])
                ++$left;
            else
                break;
        }
 
        // Go to right while height keeps increasing
        for ($j = $i + 1; $j < $n; ++$j)
        {
            if ($templeHeight[$j] < $templeHeight[$j - 1])
                ++$right;
            else
                break;
        }
 
        // This temple should offer maximum of two
        // values to follow the rule.
        $sum += max($right, $left) + 1;
    }
 
    return $sum;
}
 
// Driver code
    $arr1 = array (1, 2, 2);
    echo offeringNumber(3, $arr1) , "\n";
    $arr2 = array (1, 4, 3, 6, 2, 1);
    echo offeringNumber(6, $arr2) ,"\n";
     
// This code is contributed by ajit
?>


Javascript




<script>
    // Program to find minimum
    // total offerings required
     
    // Returns minimum
    // offerings required
    function offeringNumber(n, templeHeight)
    {
        let sum = 0; // Initialize result
 
        // Go through all
        // temples one by one
        for (let i = 0; i < n; ++i)
        {
            // Go to left while
            // height keeps increasing
            let left = 0, right = 0;
            for (let j = i - 1; j >= 0; --j)
            {
                if (templeHeight[j] < templeHeight[j + 1])
                    ++left;
                else
                    break;
            }
 
            // Go to right while
            // height keeps increasing
            for (let j = i + 1; j < n; ++j)
            {
                if (templeHeight[j] < templeHeight[j - 1])
                    ++right;
                else
                    break;
            }
 
            // This temple should offer
            // maximum of two values
            // to follow the rule.
            sum += Math.max(right, left) + 1;
        }
 
        return sum;
    }
         
      let arr1 = [1, 2, 2];
    document.write(offeringNumber(3, arr1) + "</br>");
      
    let arr2 = [1, 4, 3, 6, 2, 1];
    document.write(offeringNumber(6, arr2));
</script>


Output

4
10

Time Complexity: O(n2
Auxiliary Space: O(1) 

Dynamic Programming Approach: 

By using Dynamic Programming, we can improve the time complexity. In this method, we create a structure of length n which maintains the maximum decreasing chain to the left of each temple and the maximum decreasing chain to the right of each temple. We go through once from 0 to N setting the value of left for each temple. We then go from N to 0 setting the value of right for each temple. We then compare the two and pick the maximum for each temple.

C++




// C++ Program to find total offerings required
#include <iostream>
using namespace std;
 
// To store count of increasing order temples
// on left and right (including current temple)
struct Temple {
    int L;
    int R;
};
 
// Returns count of minimum offerings for
// n temples of given heights.
int offeringNumber(int n, int templeHeight[])
{
    // Initialize counts for all temples
    Temple chainSize[n];
    for (int i = 0; i < n; ++i) {
        chainSize[i].L = -1;
        chainSize[i].R = -1;
    }
 
    // Values corner temples
    chainSize[0].L = 1;
    chainSize[n - 1].R = 1;
 
    // Filling left and right values using same
    // values of previous(or next)
    for (int i = 1; i < n; ++i) {
        if (templeHeight[i - 1] < templeHeight[i])
            chainSize[i].L = chainSize[i - 1].L + 1;
        else
            chainSize[i].L = 1;
    }
    for (int i = n - 2; i >= 0; --i) {
        if (templeHeight[i + 1] < templeHeight[i])
            chainSize[i].R = chainSize[i + 1].R + 1;
        else
            chainSize[i].R = 1;
    }
 
    // Computing max of left and right for all
    // temples and returning sum.
    int sum = 0;
    for (int i = 0; i < n; ++i)
        sum += max(chainSize[i].L, chainSize[i].R);
    return sum;
}
 
// Driver function
int main()
{
    int arr1[3] = { 1, 2, 2 };
    cout << offeringNumber(3, arr1) << "\n";
    int arr2[6] = { 1, 4, 3, 6, 2, 1 };
    cout << offeringNumber(6, arr2) << "\n";
    return 0;
}


Java




// Java program to find total offerings required
import java.util.*;
 
class GFG {
 
    // To store count of increasing order temples
    // on left and right (including current temple)
    public static class Temple {
        public int L;
        public int R;
    };
 
    // Returns count of minimum offerings for
    // n temples of given heights.
    static int offeringNumber(int n, int[] templeHeight)
    {
 
        // Initialize counts for all temples
        Temple[] chainSize = new Temple[n];
 
        for (int i = 0; i < n; ++i) {
            chainSize[i] = new Temple();
            chainSize[i].L = -1;
            chainSize[i].R = -1;
        }
 
        // Values corner temples
        chainSize[0].L = 1;
        chainSize[n - 1].R = 1;
 
        // Filling left and right values
        // using same values of
        // previous(or next)
        for (int i = 1; i < n; ++i) {
            if (templeHeight[i - 1] < templeHeight[i])
                chainSize[i].L = chainSize[i - 1].L + 1;
            else
                chainSize[i].L = 1;
        }
 
        for (int i = n - 2; i >= 0; --i) {
            if (templeHeight[i + 1] < templeHeight[i])
                chainSize[i].R = chainSize[i + 1].R + 1;
            else
                chainSize[i].R = 1;
        }
 
        // Computing max of left and right for all
        // temples and returning sum.
        int sum = 0;
        for (int i = 0; i < n; ++i)
            sum += Math.max(chainSize[i].L, chainSize[i].R);
 
        return sum;
    }
 
    // Driver code
    public static void main(String[] s)
    {
        int[] arr1 = { 1, 2, 2 };
        System.out.println(offeringNumber(3, arr1));
 
        int[] arr2 = { 1, 4, 3, 6, 2, 1 };
        System.out.println(offeringNumber(6, arr2));
    }
}
 
// This code is contributed by pratham76


Python3




# Python3 program to find temple
# offerings required
from typing import List
 
# To store count of increasing order temples
# on left and right (including current temple)
 
 
class Temple:
    def __init__(self, l: int, r: int):
 
        self.L = l
        self.R = r
 
# Returns count of minimum offerings for
# n temples of given heights.
 
 
def offeringNumber(n: int,
                   templeHeight: List[int]) -> int:
 
    # Initialize counts for all temples
    chainSize = [0] * n
 
    for i in range(n):
        chainSize[i] = Temple(-1, -1)
 
    # Values corner temples
    chainSize[0].L = 1
    chainSize[-1].R = 1
 
    # Filling left and right values
    # using same values of previous(or next
    for i in range(1, n):
        if templeHeight[i - 1] < templeHeight[i]:
            chainSize[i].L = chainSize[i - 1].L + 1
        else:
            chainSize[i].L = 1
 
    for i in range(n - 2, -1, -1):
        if templeHeight[i + 1] < templeHeight[i]:
            chainSize[i].R = chainSize[i + 1].R + 1
        else:
            chainSize[i].R = 1
 
    # Computing max of left and right for all
    # temples and returning sum
    sm = 0
    for i in range(n):
        sm += max(chainSize[i].L,
                  chainSize[i].R)
 
    return sm
 
 
# Driver code
if __name__ == '__main__':
 
    arr1 = [1, 2, 2]
    print(offeringNumber(3, arr1))
 
    arr2 = [1, 4, 3, 6, 2, 1]
    print(offeringNumber(6, arr2))
 
# This code is contributed by Rajat Srivastava


C#




// C# program to find total offerings required
using System;
 
class GFG {
 
    // To store count of increasing order temples
    // on left and right (including current temple)
    public class Temple {
        public int L;
        public int R;
    };
 
    // Returns count of minimum offerings for
    // n temples of given heights.
    static int offeringNumber(int n, int[] templeHeight)
    {
 
        // Initialize counts for all temples
        Temple[] chainSize = new Temple[n];
 
        for (int i = 0; i < n; ++i) {
            chainSize[i] = new Temple();
            chainSize[i].L = -1;
            chainSize[i].R = -1;
        }
 
        // Values corner temples
        chainSize[0].L = 1;
        chainSize[n - 1].R = 1;
 
        // Filling left and right values
        // using same values of
        // previous(or next)
        for (int i = 1; i < n; ++i) {
            if (templeHeight[i - 1] < templeHeight[i])
                chainSize[i].L = chainSize[i - 1].L + 1;
            else
                chainSize[i].L = 1;
        }
        for (int i = n - 2; i >= 0; --i) {
            if (templeHeight[i + 1] < templeHeight[i])
                chainSize[i].R = chainSize[i + 1].R + 1;
            else
                chainSize[i].R = 1;
        }
 
        // Computing max of left and right for all
        // temples and returning sum.
        int sum = 0;
        for (int i = 0; i < n; ++i)
            sum += Math.Max(chainSize[i].L, chainSize[i].R);
 
        return sum;
    }
 
    // Driver code
    static void Main()
    {
        int[] arr1 = { 1, 2, 2 };
        Console.Write(offeringNumber(3, arr1) + "\n");
 
        int[] arr2 = { 1, 4, 3, 6, 2, 1 };
        Console.Write(offeringNumber(6, arr2) + "\n");
    }
}
 
// This code is contributed by rutvik_56


Javascript




// Javascript code for the above approach
const offeringNumber = (n, templeHeight) => {
 
// Initialize counts for all temples
let chainSize = new Array(n);
for (let i = 0; i < n; ++i) {
chainSize[i] = { L: -1, R: -1 };
}
 
// Values corner temples
chainSize[0].L = 1;
chainSize[n - 1].R = 1;
 
// Filling left and right values using same
// values of previous(or next)
for (let i = 1; i < n; ++i) {
    if (templeHeight[i - 1] < templeHeight[i])
        chainSize[i].L = chainSize[i - 1].L + 1;
    else
        chainSize[i].L = 1;
}
for (let i = n - 2; i >= 0; --i) {
    if (templeHeight[i + 1] < templeHeight[i])
        chainSize[i].R = chainSize[i + 1].R + 1;
    else
        chainSize[i].R = 1;
}
 
// Computing max of left and right for all
// temples and returning sum.
let sum = 0;
for (let i = 0; i < n; ++i)
    sum += Math.max(chainSize[i].L, chainSize[i].R);
return sum;
}
 
// Driver function
let arr = [1,2,2]
console.log(offeringNumber(3, arr));
let arr1=[1, 4, 3, 6, 2, 1]
console.log(offeringNumber(6, arr1));
 
// This code is contributed by lokeshpotta20.


Output

4
10

Time Complexity: O(n) 
Auxiliary Space: O(n)

Greedy Approach:

If we somehow manage to make sure that the temple at higher mountain is getting more offerings then our problem is solved. For this we can make use of greedy (since we have to compare only the neighbors of current index). The approach is to do two traversals (in two directions), first one to make sure that the temple gets more offerings than the left temple (at higher position) and second one to make sure that the temple at higher position from the right gets more offerings. 

C++




// C++ Program to find total offerings required
#include <iostream>
using namespace std;
 
int templeOfferings(int nums[], int n)
{
  // to find the total offerings in both directions
  int offerings[n];
 
  // start off by giving one offering to the first
  // temple
  offerings[0] = 1;
 
  // to make sure that the temple at ith position gets
  // more offerings if it is at a greater height than
  // the left one
  for (int i = 1; i < n; i++)
  {
    if (nums[i] > nums[i - 1])
      offerings[i] = offerings[i - 1] + 1;
    else
      offerings[i] = 1;
  }
 
  // to make sure that the temple at ith position gets
  // more offerings if it is at a greater height than
  // the right one
  for (int i = n - 2; i >= 0; i--)
  {
    if (nums[i] > nums[i + 1] && offerings[i] <= offerings[i + 1])
      offerings[i] = offerings[i + 1] + 1;
  }
 
  // total offerings
  int sum = 0;
  for (int val : offerings)
    sum += val;
  return sum;
}
 
// Driver function
int main()
{
  int arr[] = { 1, 4, 3, 6, 2, 1 };
  int n = sizeof(arr)/sizeof(arr[0]);
  cout << (templeOfferings(arr, n));
  return 0;
}
 
// This code is contributed by kothavvsaakash


Java




/*package whatever //do not write package name here */
 
import java.io.*;
 
class GFG {
    public static void main(String[] args)
    {
        int[] arr = { 1, 4, 3, 6, 2, 1 };
        int n = arr.length;
        System.out.println(templeOfferings(arr, n));
    }
 
    private static int templeOfferings(int[] nums, int n)
    {
        // to find the total offerings in both directions
        int[] offerings = new int[n];
 
        // start off by giving one offering to the first
        // temple
        offerings[0] = 1;
 
        // to make sure that the temple at ith position gets
        // more offerings if it is at a greater height than
        // the left one
        for (int i = 1; i < n; i++) {
            if (nums[i] > nums[i - 1])
                offerings[i] = offerings[i - 1] + 1;
            else
                offerings[i] = 1;
        }
 
        // to make sure that the temple at ith position gets
        // more offerings if it is at a greater height than
        // the right one
        for (int i = n - 2; i >= 0; i--) {
            if (nums[i] > nums[i + 1]
                && offerings[i] <= offerings[i + 1])
                offerings[i] = offerings[i + 1] + 1;
        }
 
        // total offerings
        int sum = 0;
        for (int val : offerings)
            sum += val;
        return sum;
    }
}


Javascript




// Javascript Program to find total offerings required
 
function templeOfferings( nums,  n)
{
  // to find the total offerings in both directions
  let offerings=new Array(n);
 
  // start off by giving one offering to the first
  // temple
  offerings[0] = 1;
 
  // to make sure that the temple at ith position gets
  // more offerings if it is at a greater height than
  // the left one
  for (let i = 1; i < n; i++)
  {
    if (nums[i] > nums[i - 1])
      offerings[i] = offerings[i - 1] + 1;
    else
      offerings[i] = 1;
  }
 
  // to make sure that the temple at ith position gets
  // more offerings if it is at a greater height than
  // the right one
  for (let i = n - 2; i >= 0; i--)
  {
    if (nums[i] > nums[i + 1] && offerings[i] <= offerings[i + 1])
      offerings[i] = offerings[i + 1] + 1;
  }
 
  // total offerings
  let sum = 0;
  for (let val of offerings)
    sum += val;
  return sum;
}
 
// Driver function
let arr = [ 1, 4, 3, 6, 2, 1 ];
let n = arr.length;
console.log(templeOfferings(arr, n));


C#




// C# Program to find total offerings required
 
using System;
using System.Linq;
using System.Collections.Generic;
 
class GFG
{
 
    static int templeOfferings(int[] nums, int n)
    {
      // to find the total offerings in both directions
      int[] offerings=new int[n];
     
      // start off by giving one offering to the first
      // temple
      offerings[0] = 1;
     
      // to make sure that the temple at ith position gets
      // more offerings if it is at a greater height than
      // the left one
      for (int i = 1; i < n; i++)
      {
        if (nums[i] > nums[i - 1])
          offerings[i] = offerings[i - 1] + 1;
        else
          offerings[i] = 1;
      }
     
      // to make sure that the temple at ith position gets
      // more offerings if it is at a greater height than
      // the right one
      for (int i = n - 2; i >= 0; i--)
      {
        if (nums[i] > nums[i + 1] && offerings[i] <= offerings[i + 1])
          offerings[i] = offerings[i + 1] + 1;
      }
     
      // total offerings
      int sum = 0;
      foreach (int val in offerings)
        sum += val;
      return sum;
    }
     
    // Driver function
    static public void Main()
    {
      int[] arr = { 1, 4, 3, 6, 2, 1 };
      int n = arr.Length;
      Console.Write(templeOfferings(arr, n));
    }
}


Python3




# Python3 code to find total offerings required
 
def templeOfferings(nums, n):
    # to find the total offerings in both directions
    offerings = [0] * n
 
    # start off by giving one offering to the first
    # temple
    offerings[0] = 1
 
    # to make sure that the temple at ith position gets
    # more offerings if it is at a greater height than
    # the left one
    for i in range(1, n):
        if nums[i] > nums[i - 1]:
            offerings[i] = offerings[i - 1] + 1
        else:
            offerings[i] = 1
 
    # to make sure that the temple at ith position gets
    # more offerings if it is at a greater height than
    # the right one
    for i in range(n - 2, -1, -1):
        if nums[i] > nums[i + 1] and offerings[i] <= offerings[i + 1]:
            offerings[i] = offerings[i + 1] + 1
 
    # total offerings
    return sum(offerings)
 
# Driver function
if __name__ == "__main__":
    arr = [1, 4, 3, 6, 2, 1]
    n = len(arr)
    print(templeOfferings(arr, n))


Output

10

Time Complexity: O(n) 
Auxiliary Space: O(n)

This article is contributed by Aditya Kamath and improved by Vishal Jha. 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.
Please write comments if you find anything incorrect, or you want to share more information about the topic discussed above.
 

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