📜  字典序最小且元素总和为 <= X 的索引顺序

📅  最后修改于: 2021-10-26 05:34:57             🧑  作者: Mango

给定一个数组arr[]和一个整数X ,任务是找到这样的索引:

  1. 找到的索引上的元素总和≤ X
  2. 索引的数量是最大可能的。
  3. 索引的顺序是字典序最小的,即 {0, 0, 1} 在字典序上小于 {1, 0, 0}

请注意,可以多次选择任何索引。
例子:

方法:这个问题看起来像是动态规划的变体,但事实证明它可以通过简单的贪心算法解决。
设具有第一个最小值的索引为 m。那么完成的最大索引数是 n = X / A[m]。所以 ans = [m, m, m, …., m],其中 m 的数量是 n,是所选索引的最大数量的顺序,总和 = nx A[m]。我们也确信最优答案有 n 个值,并且不超过这个值。
现在,如果我们可以找到一个小于 m 的索引 i,我们可以用相同数量的所选索引获得字典序较小的顺序,这样我们就可以用值 A[i] 的索引替换值 A[m] 的索引] 在不超过总和 X 的情况下,我们可以用 i 替换 ans 中的第一个元素,使顺序在字典上更小。为了使它在字典上尽可能小,我们希望索引 i 尽可能小,然后我们希望尽可能多地使用它。

下面是上述方法的实现:

C++
// C++ implementation of the approach
#include 
using namespace std;
 
// Function to return the chosen indices
vector solve(int X, vector& A)
{
    int min = INT_MAX;
    int ind = -1;
 
    for (int i = 0; i < A.size(); i++) {
        if (A[i] < min) {
            min = A[i];
            ind = i;
        }
    }
 
    // Maximum indices chosen
    int maxIndChosen = X / min;
 
    vector ans;
 
    if (maxIndChosen == 0) {
        return ans;
    }
 
    for (int i = 0; i < maxIndChosen; i++) {
        ans.push_back(ind);
    }
 
    int temp = maxIndChosen;
    int sum = maxIndChosen * A[ind];
 
    // Try to replace the first element in ans by i,
    // making the order lexicographically smaller
    for (int i = 0; i < ind; i++) {
 
        // If no further replacement possible return
        if (sum - X == 0 || temp == 0)
            break;
 
        // If found an index smaller than ind and sum
        // not exceeding X then remove index of smallest
        // value from ans and then add index i to ans
        while ((sum - A[ind] + A[i]) <= X && temp != 0) {
            ans.erase(ans.begin());
            ans.push_back(i);
            temp--;
            sum += (A[i] - A[ind]);
        }
    }
 
    sort(ans.begin(), ans.end());
 
    return ans;
}
 
// Driver code
int main()
{
    vector A = { 5, 6, 4, 8 };
    int X = 18;
 
    vector ans = solve(X, A);
 
    // Print the chosen indices
    for (int i = 0; i < ans.size(); i++)
        cout << ans[i] << " ";
 
    return 0;
}


Java
// Java implementation of the approach
import java.util.*;
 
class GFG
{
 
// Function to return the chosen indices
static Vector solve(int X, Vector A)
{
    int min = Integer.MAX_VALUE;
    int ind = -1;
 
    for (int i = 0; i < A.size(); i++)
    {
        if (A.get(i) < min)
        {
            min = A.get(i);
            ind = i;
        }
    }
 
    // Maximum indices chosen
    int maxIndChosen = X / min;
 
    Vector ans = new Vector<>();
 
    if (maxIndChosen == 0)
    {
        return ans;
    }
 
    for (int i = 0; i < maxIndChosen; i++)
    {
        ans.add(ind);
    }
 
    int temp = maxIndChosen;
    int sum = maxIndChosen * A.get(ind);
 
    // Try to replace the first element in ans by i,
    // making the order lexicographically smaller
    for (int i = 0; i < ind; i++) {
 
        // If no further replacement possible return
        if (sum - X == 0 || temp == 0)
            break;
 
        // If found an index smaller than ind and sum
        // not exceeding X then remove index of smallest
        // value from ans and then add index i to ans
        while ((sum - A.get(ind) + A.get(i)) <= X && temp != 0)
        {
            ans.remove(0);
            ans.add(i);
            temp--;
            sum += (A.get(i) - A.get(ind));
        }
    }
 
    Collections.sort(ans);
 
    return ans;
}
 
// Driver code
public static void main(String args[])
{
    Integer arr[] = { 5, 6, 4, 8 };
    Vector A = new Vector(Arrays.asList(arr));
    int X = 18;
 
    Vector ans = solve(X, A);
 
    // Print the chosen indices
    for (int i = 0; i < ans.size(); i++)
        System.out.print(ans.get(i)+" ");
}
}
 
/* This code contributed by PrinciRaj1992 */


Python3
# Python3 implementation of the approach
import sys;
 
# Function to return the chosen indices
def solve(X, A) :
 
    minimum = sys.maxsize;
    ind = -1;
     
    for i in range(len(A)) :
        if (A[i] < minimum ) :
            minimum = A[i];
            ind = i;
     
    # Maximum indices chosen
    maxIndChosen = X // minimum ;
     
    ans = [];
     
    if (maxIndChosen == 0) :
        return ans;
         
    for i in range(maxIndChosen) :
        ans.append(ind);
         
    temp = maxIndChosen;
    sum = maxIndChosen * A[ind];
     
    # Try to replace the first element in ans by i,
    # making the order lexicographically smaller
    for i in range(ind) :
         
        # If no further replacement possible return
        if (sum - X == 0 or temp == 0) :
            break;
             
        # If found an index smaller than ind and sum
        # not exceeding X then remove index of smallest
        # value from ans and then add index i to ans
        while ((sum - A[ind] + A[i]) <= X and temp != 0) :
            del(ans[0]);
            ans.append(i);
            temp -= 1;
            sum += (A[i] - A[ind]);
             
    ans.sort();
    return ans;
 
 
# Driver code
if __name__ == "__main__" :
 
    A = [ 5, 6, 4, 8 ];
    X = 18;
 
    ans = solve(X, A);
 
    # Print the chosen indices
    for i in range(len(ans)) :
        print(ans[i],end= " ");
 
# This code is contributed by AnkitRai01


C#
// C# implementation of the approach
using System;
using System.Collections.Generic;
     
class GFG
{
 
// Function to return the chosen indices
static List solve(int X, List A)
{
    int min = int.MaxValue;
    int ind = -1;
 
    for (int i = 0; i < A.Count; i++)
    {
        if (A[i] < min)
        {
            min = A[i];
            ind = i;
        }
    }
 
    // Maximum indices chosen
    int maxIndChosen = X / min;
 
    List ans = new List();
 
    if (maxIndChosen == 0)
    {
        return ans;
    }
 
    for (int i = 0; i < maxIndChosen; i++)
    {
        ans.Add(ind);
    }
 
    int temp = maxIndChosen;
    int sum = maxIndChosen * A[ind];
 
    // Try to replace the first element in ans by i,
    // making the order lexicographically smaller
    for (int i = 0; i < ind; i++)
    {
 
        // If no further replacement possible return
        if (sum - X == 0 || temp == 0)
            break;
 
        // If found an index smaller than ind and sum
        // not exceeding X then remove index of smallest
        // value from ans and then add index i to ans
        while ((sum - A[ind] + A[i]) <= X && temp != 0)
        {
            ans.RemoveAt(0);
            ans.Add(i);
            temp--;
            sum += (A[i] - A[ind]);
        }
    }
 
    ans.Sort();
 
    return ans;
}
 
// Driver code
public static void Main(String []args)
{
    int []arr = { 5, 6, 4, 8 };
    List A = new List(arr);
    int X = 18;
 
    List ans = solve(X, A);
 
    // Print the chosen indices
    for (int i = 0; i < ans.Count; i++)
        Console.Write(ans[i] + " ");
}
}
 
// This code is contributed by 29AjayKumar


Javascript


输出:
0 0 2 2

时间复杂度: O(NLog(N))

如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程学生竞争性编程现场课程