📌  相关文章
📜  数组范围查询以找到具有更新的最大Armstrong数

📅  最后修改于: 2021-04-24 20:47:32             🧑  作者: Mango

给定N个整数的数组arr [] ,任务是执行以下两个查询:

  • maximum(start,end) :从头到尾打印子数组中的最大Armstrong元素数
  • update(i,x) :将x添加到数组索引i引用的数组元素中,即:arr [i] = x

如果子数组中没有阿姆斯壮编号,则打印-1

例子:

简单的解决方案:
一个简单的解决方案是从l到r循环运行,并计算给定范围内的最大Armstrong元素数量。要更新值,只需做arr [i] = x。第一次操作花费O(N)时间,第二次操作花费O(1)时间。

高效方法:

  • 一种有效的方法是构建一个“分段树”,其中每个节点都存储两个值( valuemax_set_bits ),并对其进行范围查询以找到最大的阿姆斯特朗数。
  • 如果我们深入研究,则任意两个范围组合的最大阿姆斯壮数将是左侧的最大阿姆斯壮数或右侧的最大阿姆斯壮数,以最大值为准。
  • 段树的表示形式:
    1. 叶节点是给定数组的元素。
    2. 每个内部节点代表其所有子节点的最大Armstrong编号,如果范围内不存在Armstrong编号,则为-1。
    3. 树的数组表示形式用于表示段树。对于索引i处的每个节点,左子节点在索引2 * i + 1处,右子节点在索引2 * i + 2处,父节点在(i-1)/ 2处
  • 从给定数组构造细分树:
    1. 我们从一个段arr [0开始。 。 。 [n-1],并且每次我们将当前段分成两半(如果尚未变成长度为1的段),然后在这两个半段上调用相同的过程,则对于每个这样的段,我们都会存储最大值段树节点中的Armstrong数值或-1。除最后一个级别外,已构建的段树的所有级别都将完全填充。而且,该树将是完整的二叉树,因为我们总是在每个级别将分段分为两半。由于构造的树始终是具有n个叶子的完整二叉树,因此将有n-1个内部节点。因此,总节点数将为2 * n – 1 。段树的高度将为log 2 n 。由于树是使用数组表示的,并且必须保持父索引和子索引之间的关系,因此分配给段树的内存大小将为2 *(2 ceil(log 2 n) )– 1
    2. n位数的正整数称为n阶的阿姆斯特朗数(阶数为数字),如果
  • 为了检查阿姆斯特朗(Armstrong)数字,我们的想法是首先计算数字位数(或查找顺序)。令数字为n。对于输入数字x中的每个数字r,计算r n 。如果所有这些值的总和等于n,则返回true,否则返回false。
  • 然后,我们在段树上进行范围查询,以找出给定范围的最大Armstrong数并输出相应的值。

下面是上述方法的实现:

C++
// C++ code to implement above approach
 
#include 
using namespace std;
 
// A utility function to get the
// middle index of given range.
int getMid(int s, int e)
{
    return s + (e - s) / 2;
}
 
// Function that return true
// if num is armstrong
// else return false
bool isArmstrong(int x)
{
    int n = to_string(x).size();
    int sum1 = 0;
    int temp = x;
    while (temp > 0) {
        int digit = temp % 10;
        sum1 += pow(digit, n);
        temp /= 10;
    }
    if (sum1 == x)
        return true;
    return false;
}
 
/*  A recursive function to get
    the sum of values in the
    given range of the array.
    The following are parameters
    for this function.
 
st -> Pointer to segment tree
node -> Index of current node in
        the segment tree .
ss & se -> Starting and ending indexes
           of the segment represented
           by current node,
           i.e., st[node]
l & r -> Starting and ending indexes
         of range query */
int MaxUtil(
    int* st, int ss, int se, int l,
    int r, int node)
{
 
    // If segment of this node is
    // completely part of given range,
    // then return the max of segment.
    if (l <= ss && r >= se)
        return st[node];
 
    // If segment of this node does not
    // belong to given range
    if (se < l || ss > r)
        return -1;
 
    // If segment of this node is
    // partially the part of given
    // range
    int mid = getMid(ss, se);
 
    return max(
        MaxUtil(st, ss, mid,
                l, r, 2 * node + 1),
        MaxUtil(st, mid + 1, se,
                l, r, 2 * node + 2));
}
 
/* A recursive function to update
   the nodes which have the given
   the index in their range. The
   following are parameters st, ss
   and se are same as defined above
   index -> index of the element
   to be updated.*/
 
void updateValue(int arr[],
                 int* st,int ss,
                 int se, int index,
                 int value, int node) {
 
    if (index < ss || index > se) {
        cout << "Invalid Input" << endl;
        return;
    }
 
    if (ss == se) {
        // update value in array
        // and in segment tree
        arr[index] = value;
 
        if (isArmstrong(value))
            st[node] = value;
        else
            st[node] = -1;
    }
    else {
        int mid = getMid(ss, se);
 
        if (index >= ss && index <= mid)
            updateValue(arr, st, ss,
                        mid, index, value,
                        2 * node + 1);
        else
            updateValue(arr, st, mid + 1,
                        se, index, value,
                        2 * node + 2);
 
        st[node] = max(st[2 * node + 1],
                       st[2 * node + 2]);
    }
    return;
}
 
// Return max of elements in
// range from index
// l (query start) to r (query end).
 
int getMax(int* st, int n,
           int l, int r)
{
    // Check for erroneous input values
    if (l < 0 || r > n - 1
        || l > r) {
        printf("Invalid Input");
        return -1;
    }
 
    return MaxUtil(st, 0, n - 1,
                   l, r, 0);
}
 
// A recursive function that
// constructs Segment Tree for
// array[ss..se]. si is index of
// current node in segment tree st
int constructSTUtil(int arr[],
                    int ss, int se,
                    int* st, int si)
{
    // If there is one
    // element in array, store
    // it in current node of
    // segment tree and return
    if (ss == se) {
        if (isArmstrong(arr[ss]))
            st[si] = arr[ss];
        else
            st[si] = -1;
        return st[si];
    }
 
    // If there are more than
    // one elements, then
    // recur for left and right
    // subtrees and store the
    // max of values in this node
 
    int mid = getMid(ss, se);
 
    st[si] = max(constructSTUtil(
                     arr, ss, mid, st,
                     si * 2 + 1),
                 constructSTUtil(
                     arr, mid + 1, se,
                     st, si * 2 + 2));
 
    return st[si];
}
 
/* Function to construct a segment tree
   from given array. This function
   allocates memory for segment tree.*/
 
int* constructST(int arr[], int n)
{
    // Height of segment tree
    int x = (int)(ceil(log2(n)));
 
    // Maximum size of segment tree
    int max_size
        = 2 * (int)pow(2, x) - 1;
 
    // Allocate memory
    int* st = new int[max_size];
 
    // Fill the allocated memory st
    constructSTUtil(arr, 0,
                    n - 1, st, 0);
 
    // Return the constructed
    // segment tree
    return st;
}
 
// Driver code
int main()
{
    int arr[] = { 192, 113,
                  535, 7, 19, 111 };
    int n = sizeof(arr) / sizeof(arr[0]);
 
    // Build segment tree from
    // given array
    int* st = constructST(arr, n);
 
    // Print max of values in array
    // from index 1 to 3
    cout << "Maximum armstrong "
         << "number in given range = "
         << getMax(st, n, 1, 3) << endl;
 
    // Update: set arr[1] = 153 and update
    // corresponding segment tree nodes.
    updateValue(arr, st, 0,
                n - 1, 1, 153, 0);
 
    // Find max after the value is updated
    cout << "Updated Maximum armstrong "
         << "number in given range = "
         << getMax(st, n, 1, 3) << endl;
 
    return 0;
}


Java
// Java code to implement
// the above approach
import java.util.*;
class GFG{
 
// A utility function to get the
// middle index of given range.
static int getMid(int s, int e)
{
    return s + (e - s) / 2;
}
 
// Function that return true
// if num is armstrong
// else return false
static boolean isArmstrong(int x)
{
    int n = String.valueOf(x).length();
    int sum1 = 0;
    int temp = x;
    while (temp > 0)
    {
        int digit = temp % 10;
        sum1 += Math.pow(digit, n);
        temp /= 10;
    }
    if (sum1 == x)
        return true;
    return false;
}
 
/* A recursive function to get
the sum of values in the
given range of the array.
The following are parameters
for this function.
st.Pointer to segment tree
node.Index of current node in
the segment tree .
ss & se.Starting and ending indexes
of the segment represented
by current node, i.e., st[node]
l & r.Starting and ending indexes
of range query */
static int MaxUtil(int []st, int ss,
                   int se, int l,
                   int r, int node)
{
    // If segment of this node is
    // completely part of given range,
    // then return the max of segment.
    if (l <= ss && r >= se)
        return st[node];
 
    // If segment of this node does not
    // belong to given range
    if (se < l || ss > r)
        return -1;
 
    // If segment of this node is
    // partially the part of given
    // range
    int mid = getMid(ss, se);
 
    return Math.max(MaxUtil(st, ss, mid,
                            l, r, 2 * node ),
                    MaxUtil(st, mid + 1,
                            se, l, r,
                            2 * node + 1));
}
 
/* A recursive function to update
the nodes which have the given
the index in their range. The
following are parameters st, ss
and se are same as defined above
index.index of the element
to be updated.*/
static void updateValue(int arr[],
                        int []st,int ss,
                        int se, int index,
                        int value, int node)
{
    if (index < ss || index > se)
    {
        System.out.print("Invalid Input" + "\n");
        return;
    }
 
    if (ss == se)
    {
        // update value in array
        // and in segment tree
        arr[index] = value;
 
        if (isArmstrong(value))
            st[node] = value;
        else
            st[node] = -1;
    }
    else
    {
        int mid = getMid(ss, se);
 
        if (index >= ss && index <= mid)
            updateValue(arr, st, ss,
                        mid, index,
                        value, 2 * node);
        else
            updateValue(arr, st, mid + 1,
                        se, index, value,
                        2 * node +1);
 
        st[node] = Math.max(st[2 * node + 1],
                            st[2 * node + 2]);
    }
    return;
}
 
// Return max of elements in
// range from index
// l (query start) to r (query end).
static int getMax(int []st, int n,
                  int l, int r)
{
    // Check for erroneous input values
    if (l < 0 || r > n - 1 ||
        l > r)
    {
        System.out.printf("Invalid Input");
        return -1;
    }
 
    return MaxUtil(st, 0, n - 1,
                       l, r, 0);
}
 
// A recursive function that
// constructs Segment Tree for
// array[ss..se]. si is index of
// current node in segment tree st
static int constructSTUtil(int arr[],
                           int ss, int se,
                           int []st, int si)
{
    // If there is one
    // element in array, store
    // it in current node of
    // segment tree and return
    if (ss == se)
    {
        if (isArmstrong(arr[ss]))
            st[si] = arr[ss];
        else
            st[si] = -1;
        return st[si];
    }
 
    // If there are more than
    // one elements, then
    // recur for left and right
    // subtrees and store the
    // max of values in this node
 
    int mid = getMid(ss, se);
 
    st[si] = Math.max(constructSTUtil(arr, ss,
                                      mid, st,
                                      si * 2 ),
                      constructSTUtil(arr, mid + 1,
                                      se, st,
                                      si * 2 + 1));
 
    return st[si];
}
 
/* Function to cona segment tree
from given array. This function
allocates memory for segment tree.*/
static int[] constructST(int arr[], int n)
{
    // Height of segment tree
    int x = (int)(Math.ceil(Math.log(n)));
 
    // Maximum size of segment tree
    int max_size = 2 * (int)Math.pow(2, x) - 1;
 
    // Allocate memory
    int []st = new int[max_size];
 
    // Fill the allocated memory st
    constructSTUtil(arr, 0,
                     n - 1, st, 0);
 
    // Return the constructed
    // segment tree
    return st;
}
 
// Driver code
public static void main(String[] args)
{
    int arr[] = {192, 113,
                 535, 7, 19, 111};
    int n = arr.length;
 
    // Build segment tree from
    // given array
    int[] st = constructST(arr, n);
 
    // Print max of values in array
    // from index 1 to 3
    System.out.print("Maximum armstrong " +
                     "number in given range = " +
                      getMax(st, n, 1, 3) + "\n");
 
    // Update: set arr[1] = 153 and update
    // corresponding segment tree nodes.
    updateValue(arr, st, 0,
                n - 1, 1, 153, 0);
 
    // Find max after the value is updated
    System.out.print("Updated Maximum armstrong " +
                       "number in given range = " +
                       getMax(st, n, 1, 3) + "\n");
 
}
}
 
// This code is contributed by gauravrajput1


Python3
# Python code to implement above approach
import math
 
# A utility function to get the
# middle index of given range.
def getMid(s: int, e: int) -> int:
    return s + (e - s) // 2
 
# Function that return true
# if num is armstrong
# else return false
def isArmstrong(x: int) -> bool:
    n = len(str(x))
    sum1 = 0
    temp = x
    while (temp > 0):
        digit = temp % 10
        sum1 += pow(digit, n)
        temp //= 10
 
    if (sum1 == x):
        return True
    return False
 
'''  A recursive function to get
    the sum of values in the
    given range of the array.
    The following are parameters
    for this function.
 
st -> Pointer to segment tree
node -> Index of current node in
        the segment tree .
ss & se -> Starting and ending indexes
           of the segment represented
           by current node,
           i.e., st[node]
l & r -> Starting and ending indexes
         of range query '''
def MaxUtil(st, ss, se, l, r, node):
 
    # If segment of this node is
    # completely part of given range,
    # then return the max of segment.
    if (l <= ss and r >= se):
        return st[node]
 
    # If segment of this node does not
    # belong to given range
    if (se < l or ss > r):
        return -1
 
    # If segment of this node is
    # partially the part of given
    # range
    mid = getMid(ss, se)
 
    return max(MaxUtil(st, ss, mid, l, r, 2 * node + 1),
               MaxUtil(st, mid + 1, se, l, r, 2 * node + 2))
 
''' A recursive function to update
   the nodes which have the given
   the index in their range. The
   following are parameters st, ss
   and se are same as defined above
   index -> index of the element
   to be updated.'''
def updateValue(arr, st, ss, se, index, value, node):
    if (index < ss or index > se):
        print("Invalid Input")
        return
    if (ss == se):
       
        # update value in array
        # and in segment tree
        arr[index] = value
        if (isArmstrong(value)):
            st[node] = value
        else:
            st[node] = -1
 
    else:
        mid = getMid(ss, se)
 
        if (index >= ss and index <= mid):
            updateValue(arr, st, ss, mid, index, value, 2 * node + 1)
        else:
            updateValue(arr, st, mid + 1, se, index, value, 2 * node + 2)
 
        st[node] = max(st[2 * node + 1], st[2 * node + 2])
    return
 
# Return max of elements in
# range from index
# l (query start) to r (query end).
def getMax(st, n, l, r):
 
    # Check for erroneous input values
    if (l < 0 or r > n - 1 or l > r):
        print("Invalid Input")
        return -1
    return MaxUtil(st, 0, n - 1, l, r, 0)
 
# A recursive function that
# constructs Segment Tree for
# array[ss..se]. si is index of
# current node in segment tree st
def constructSTUtil(arr, ss, se, st, si):
 
    # If there is one
    # element in array, store
    # it in current node of
    # segment tree and return
    if (ss == se):
        if (isArmstrong(arr[ss])):
            st[si] = arr[ss]
        else:
            st[si] = -1
        return st[si]
 
    # If there are more than
    # one elements, then
    # recur for left and right
    # subtrees and store the
    # max of values in this node
    mid = getMid(ss, se)
    st[si] = max(constructSTUtil(arr, ss, mid, st, si * 2 + 1),
                 constructSTUtil(arr, mid + 1, se, st, si * 2 + 2))
    return st[si]
 
''' Function to construct a segment tree
   from given array. This function
   allocates memory for segment tree.'''
def constructST(arr, n):
 
    # Height of segment tree
    x = int(math.ceil(math.log2(n)))
 
    # Maximum size of segment tree
    max_size = 2 * int(math.pow(2, x)) - 1
 
    # Allocate memory
    st = [0 for _ in range(max_size)]
 
    # Fill the allocated memory st
    constructSTUtil(arr, 0, n - 1, st, 0)
 
    # Return the constructed
    # segment tree
    return st
 
# Driver code
if __name__ == "__main__":
 
    arr = [192, 113, 535, 7, 19, 111]
    n = len(arr)
 
    # Build segment tree from
    # given array
    st = constructST(arr, n)
 
    # Print max of values in array
    # from index 1 to 3
    print("Maximum armstrong number in given range = {}".format(
        getMax(st, n, 1, 3)))
 
    # Update: set arr[1] = 153 and update
    # corresponding segment tree nodes.
    updateValue(arr, st, 0, n - 1, 1, 153, 0)
 
    # Find max after the value is updated
    print("Updated Maximum armstrong number in given range = {}".format(
        getMax(st, n, 1, 3)))
 
# This code is contributed by sanjeev2552


C#
// C# code to implement
// the above approach
using System;
class GFG{
 
// A utility function to get the
// middle index of given range.
static int getMid(int s, int e)
{
  return s + (e - s) / 2;
}
 
// Function that return true
// if num is armstrong
// else return false
static bool isArmstrong(int x)
{
  int n = String.Join("", x).Length;
  int sum1 = 0;
  int temp = x;
  while (temp > 0)
  {
    int digit = temp % 10;
    sum1 += (int)Math.Pow(digit, n);
    temp /= 10;
  }
  if (sum1 == x)
    return true;
  return false;
}
 
/* A recursive function to get
the sum of values in the
given range of the array.
The following are parameters
for this function.
st.Pointer to segment tree
node.Index of current node in
the segment tree .
ss & se.Starting and ending indexes
of the segment represented
by current node, i.e., st[node]
l & r.Starting and ending indexes
of range query */
static int MaxUtil(int []st, int ss,
                   int se, int l,
                   int r, int node)
{
  // If segment of this node is
  // completely part of given range,
  // then return the max of segment.
  if (l <= ss && r >= se)
    return st[node];
 
  // If segment of this node does not
  // belong to given range
  if (se < l || ss > r)
    return -1;
 
  // If segment of this node is
  // partially the part of given
  // range
  int mid = getMid(ss, se);
 
  return Math.Max(MaxUtil(st, ss, mid,
                          l, r, 2 * node),
                  MaxUtil(st, mid + 1,
                          se, l, r,
                          2 * node + 1));
}
 
/* A recursive function to update
the nodes which have the given
the index in their range. The
following are parameters st, ss
and se are same as defined above
index.index of the element
to be updated.*/
static void updateValue(int []arr,
                        int []st, int ss,
                        int se, int index,
                        int value, int node)
{
  if (index < ss || index > se)
  {
    Console.Write("Invalid Input" + "\n");
    return;
  }
 
  if (ss == se)
  {
    // update value in array
    // and in segment tree
    arr[index] = value;
 
    if (isArmstrong(value))
      st[node] = value;
    else
      st[node] = -1;
  }
  else
  {
    int mid = getMid(ss, se);
 
    if (index >= ss && index <= mid)
      updateValue(arr, st, ss,
                  mid, index,
                  value, 2 * node);
    else
      updateValue(arr, st, mid + 1,
                  se, index, value,
                  2 * node + 1);
 
    st[node] = Math.Max(st[2 * node + 1],
                        st[2 * node + 2]);
  }
  return;
}
 
// Return max of elements in
// range from index
// l (query start) to r (query end).
static int getMax(int []st, int n,
                  int l, int r)
{
  // Check for erroneous input values
  if (l < 0 || r > n - 1 ||
      l > r)
  {
    Console.Write("Invalid Input");
    return -1;
  }
 
  return MaxUtil(st, 0, n - 1,
                 l, r, 0);
}
 
// A recursive function that
// constructs Segment Tree for
// array[ss..se]. si is index of
// current node in segment tree st
static int constructSTUtil(int []arr,
                           int ss, int se,
                           int []st, int si)
{
  // If there is one
  // element in array, store
  // it in current node of
  // segment tree and return
  if (ss == se)
  {
    if (isArmstrong(arr[ss]))
      st[si] = arr[ss];
    else
      st[si] = -1;
    return st[si];
  }
 
  // If there are more than
  // one elements, then
  // recur for left and right
  // subtrees and store the
  // max of values in this node
  int mid = getMid(ss, se);
 
  st[si] = Math.Max(constructSTUtil(arr, ss,
                                    mid, st,
                                    si * 2),
                    constructSTUtil(arr, mid + 1,
                                    se, st,
                                    si * 2 + 1));
  return st[si];
}
 
/* Function to cona segment tree
from given array. This function
allocates memory for segment tree.*/
static int[] constructST(int []arr, int n)
{
  // Height of segment tree
  int x = (int)(Math.Ceiling(Math.Log(n)));
 
  // Maximum size of segment tree
  int max_size = 2 * (int)Math.Pow(2, x) - 1;
 
  // Allocate memory
  int []st = new int[max_size];
 
  // Fill the allocated memory st
  constructSTUtil(arr, 0,
                  n - 1, st, 0);
 
  // Return the constructed
  // segment tree
  return st;
}
 
// Driver code
public static void Main(String[] args)
{
  int []arr = {192, 113,
               535, 7, 19, 111};
  int n = arr.Length;
 
  // Build segment tree from
  // given array
  int[] st = constructST(arr, n);
 
  // Print max of values in array
  // from index 1 to 3
  Console.Write("Maximum armstrong " +
                "number in given range = " +
                 getMax(st, n, 1, 3) + "\n");
 
  // Update: set arr[1] = 153 and update
  // corresponding segment tree nodes.
  updateValue(arr, st, 0,
              n - 1, 1, 153, 0);
 
  // Find max after the value is updated
  Console.Write("Updated Maximum armstrong " +
                "number in given range = " +
                 getMax(st, n, 1, 3) + "\n");
}
}
 
// This code is contributed by shikhasingrajput


输出:
Maximum armstrong number in given range = 7 
Updated Maximum armstrong number in given range = 153

时间复杂度:每个查询和更新的时间复杂度为O(log N) ,构建段树的时间复杂度为O(N)