我在网上遇到了这个问题。
给定一个整数:N和一个数组int arr[],您必须向数组中添加一些元素,以便可以使用(添加)数组中的元素从1生成到N。
请记住,在生成某个x(1)时,只能使用数组中的每个元素一次
For example:
N=6, arr = [1, 3]
1 is already in arr.
add 2 to the arr.
3 is already in arr
4 = 1 + 3
5 = 2 + 3
6 = 1 + 2 + 3
So we return 1 since we only need to add one element which is 2.
有人能给点提示吗?
一种方法是生成一组由数组生成的所有可能的数字。这可以在O(n^2)时间内完成。然后,在O(1)时间内检查集合中是否存在从1到n的数字。如果数字不存在,则将其添加到最初为零的最少添加数字的计数中,并创建一个新的空集。取上一个集合的所有元素,将不存在的数字添加到它们中,然后将它们(集合添加方法)添加到新集合中。用原始集和新集的并集替换原始集。从1到n进行此操作将在O(n^3)时间内给出最小加法数之和。
设A为输入数字的集合。
初始化布尔数组B以存储在B[i]中,无论我们是否可以通过在a中添加数字来“生成”i,如问题中所述。使所有B[i]最初为假。
然后,伪代码:
for i = 1 to N
if B[i] && (not A.Contains(i))
continue next i
if not A.Contains(i)
countAdded++
for j = N-i downTo 1
if B[j] then B[j+i] = TRUE
B[i] = TRUE
next i
解释:
在(主)循环(i)中:对于我们可以用A中小于i的值构造的值,B包含TRUE。因此,最初,当i=1时,所有B都是FALSE。
那么,对于每个i,我们有两个方面需要考虑:(a)B[i]已经是真的了吗?如果不是,我们将不得不添加i;(b) 我现在在吗?因为,看前面的评论,此时我们还没有处理那个A值。所以,即使B【i】已经为真,我们也必须为所有(其他)B标记真,我们可以用i来达到。
因此:
对于每个i,我们首先确定这两种情况是否适用,如果不适用,我们跳到下一个i。
然后,如果A不(还)包含i,则必须是B[i]为FALSE的情况,请参阅跳过条件,因此我们将添加i(概念上为A,但实际上没有必要将其放入A中)。
接下来,要么我们最初在A中加入了i,要么我们刚刚添加了它。在任何情况下,我们都需要为所有可以用这个新i构造的值标记B TRUE。为此,我们最好向下扫描现有的B;否则,我们可能会将i添加到“新”B值中,该B值已将i作为组成部分。
最后,B[i]本身被设置为TRUE(它可能已经是TRUE...),仅仅是因为i在A中(原始地,或通过添加)
除了N=2和N=1之外,总是可以通过将1的子集添加到
N-1
数字来生成N
。因此,当数组中已经存在上一个到X-1的连续元素时,必须生成一个数字X。示例-
arr[] = {1, 2, 5}, N = 9
ans := 0
1 is already present.
2 is already present.
3 is absent. But prior 1 to (3 - 1) elements are present. So 3 is added in the array. But as 3 is built using already existed elements, so answer won't increase.
same rule for 4 and 5
So, ans is 0
arr[] = {3, 4}, for any N >= 2
ans = 2
arr[] = {1, 3}, for any N >= 2
ans = 1
所以,看起来,如果数组中只有
1
和2
不存在,我们必须添加该元素,而不管之前的元素是否已经在数组中。所有后面的数字都可以通过使用以前的元素来制作。并且当尝试制作任何数字X
(
因此,基本上我们需要检查是否存在
1和
2。所以这个问题的答案不会大于2
在上述算法中,我们假设,当数组中不存在新元素X,但可以使用数组中已存在的元素生成新元素时,答案不会增加,但会在数组中添加X,以用于下一个数字生成。如果无法在数组中添加X,该怎么办?
然后,基本上它会变成一个子集和问题。对于每个缺失的数字,我们必须检查该数字是否可以使用数组中的任何元素子集来生成。这是典型的
O(N^2)
动态规划算法。
int subsetSum(vector<int>& arr, int N)
{
// The value of subset[i][j] will be true if there is a subset of set[0..j-1]
// with sum equal to i
bool subset[N + 1][arr.size() + 1];
// If sum is 0, then answer is true
for (int i = 0; i <= arr.size(); i++)
subset[0][i] = true;
// If sum is not 0 and set is empty, then answer is false
for (int i = 1; i <= N; i++)
subset[i][0] = false;
// Fill the subset table in botton up manner
for (int i = 1; i <= N; i++)
{
for (int j = 1; j <= arr.size(); j++)
{
subset[i][j] = subset[i][j - 1];
if (i >= set[j - 1])
subset[i][j] = subset[i][j] || subset[i - set[j - 1]][j - 1];
}
}
unordered_map<int, bool> exist;
for(int i = 0; i < arr.size(); ++i) {
exist[arr[i]] = true;
}
int ans = 0;
for(int i = 1; i <= N; ++i) {
if(!exist[i] or !subset[i][arr.size()]) {
ans++;
}
}
return ans;
}
首先定义Dijkstra算法: Dijkstra的算法在有向图中寻找具有非负边权的单源最短路径。 如果我有源和目的地T,我可以用Dijkstra算法在这两个顶点之间找到一条最短路径,但这里的问题是我想找到这两个顶点之间的最短路径,这两个顶点之间的边数不超过形式k。 第一部分是Dijkstra算法,第二部分是BFS算法,因为我们可以用BFS算法在无权图中找到最短路径。 所以我想知道有没有一种方法,可
1 原理 迭代再加权最小二乘(IRLS)用于解决特定的最优化问题,这个最优化问题的目标函数如下所示: arg min{\beta} \sum{i=1}^{n}|y{i} - f{i}(\beta)|^{p} 这个目标函数可以通过迭代的方法求解。在每次迭代中,解决一个带权最小二乘问题,形式如下: \beta ^{t+1} = argmin{\beta} \sum{i=1}^{n} w{i}(
提到最小表示法,要了解它的定义,最小表示法是用于解决字符串最小表示问题的方法。 一算法简介: 当一个字符串形成一个环的时候,要比较两个字符串是否相同就会变得很困难,因为你不知道对于第二个字符串来说,以哪个字符开始比较才会和第一个字符串相同。 所以我们就会想到枚举起点比较是否相同,而这样的复杂度O(n^2)。而最小表示法这种算法可以在O(n)的时间解决这个问题。下面介绍一下最小表示法。 二、算法分析
最小操作数 题目描述 给定一个单词集合Dict,其中每个单词的长度都相同。现从此单词集合Dict中抽取两个单词A、B,我们希望通过若干次操作把单词A变成单词B,每次操作可以改变单词的一个字母,同时,新产生的单词必须是在给定的单词集合Dict中。求所有行得通步数最少的修改方法。 举个例子如下: Given: A = “hit” B = “cog” Dict = [“hot”,”dot”,”dog”,
Python3 实例 以下代码用于实现最小公倍数算法: 实例(Python 3.0+)# Filename : test.py # author by : www.runoob.com # 定义函数 def lcm(x, y): # 获取最大的数 if x > y: greater = x else: greater = y while(True): if((greater % x == 0) a
主要内容:Min-Max算法的工作人工智能中的最小最大算法: Mini-max算法是一种递归或回溯算法,用于决策和博弈论。它为玩家提供了一个最佳的动作,假设对手也在玩最佳状态。 Mini-Max算法使用递归来搜索游戏树。 Min-Max算法主要用于AI中的游戏。如Chess,Checkers,tic-tac-toe,go和各种拖车玩家游戏。该算法计算当前状态的最小极大决策。 在该算法中,两个玩家玩游戏,一个叫做MAX,另一个叫做M