📌  相关文章
📜  数组范围查询以查找带有更新的最大阿姆斯特朗数

📅  最后修改于: 2021-09-16 11:04:59             🧑  作者: Mango

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

  • maximum(start, end) :打印子数组中从开始到结束的最大阿姆斯特朗元素数
  • update(i, x) :将 x 添加到数组索引i 所引用的数组元素,即: arr[i] = x

如果子数组中没有阿姆斯特朗数,则打印-1

例子:

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

有效的方法:

  • 一种有效的方法是构建一个 Segment Tree,其中每个节点存储两个值( valuemax_set_bits ),并对其进行范围查询以找到最大的 Armstrong 数。
  • 如果我们深入研究它,任何两个范围组合的最大阿姆斯特朗数要么是左侧的最大阿姆斯特朗数,要么是右侧的最大阿姆斯特朗数,以最大值为准。
  • 段树的表示:
    1. 叶节点是给定数组的元素。
    2. 每个内部节点代表其所有子节点的最大阿姆斯壮数,或者 -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 阶阿姆斯特朗数(阶数是位数),如果
  • 为了检查阿姆斯特朗数,想法是首先计算数字位数(或查找顺序)。设位数为n。对于输入数字 x 中的每个数字 r,计算 r n 。如果所有这些值的总和等于 n,则返回 true 否则返回 false。
  • 然后我们对线段树进行范围查询,找出给定范围的最大阿姆斯特朗数并输出相应的值。

下面是上述方法的实现:

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


Javascript


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

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