Здравствуйте, на Hackerrank решил задачу о размене монет с использованием мемоизации. Однако, мне моё решение, кажется не очень оптимальным. Как его можно улучшить?
Условие.
public static long GetWays(int units, int[] coins, Dictionary<string, long> mem)
{
if (units < 0 || coins.Length == 0) return 0;
if (units == 0) return 1;
var newCoins = new int[coins.Length - 1];
Array.Copy(coins, 1, newCoins, 0, coins.Length - 1);
var coinsStr = string.Join(",", coins) + units;
var newCoinsStr = string.Join(",", newCoins) + units;
var newUnitStr = string.Join(",", coins) + (units - coins[0]);
long answer = 0;
if (mem.ContainsKey(newCoinsStr)) answer += mem[newCoinsStr];
else answer += GetWays(units, newCoins, mem);
if (mem.ContainsKey(newUnitStr)) answer += mem[newUnitStr];
else answer += GetWays(units - coins[0], coins, mem);
if (!mem.ContainsKey(coinsStr)) mem.Add(coinsStr, answer);
return answer;
}
И еще один вопрос. Я на самом деле не очень понимаю, почему число способов разменять сумму s равно числу способов разменять s с использованием n-1 типом монет + числу способов разменять сумму s - w с использование всех n типов монет. w - достоинство исключенной. Спасибо.
upd. странно, что ссылка не работает. Вставил скриншот условия, дабыл не перепечатывать.
Кхм, какой вопрос такой и ответ. Решение ужасное. В этой задаче меморизация совсем не нужна, меморизация по строкам - вообще ужас. Вам же прямо в условии написали как решать. Те кто понимают, плюются) Более-менее нормальное решение (на С++ правда).
long getWays(long n, vector < long > c){
long DP[255];
memset(DP,0,sizeof(DP)); //в C# и так будет 0, С++ надо
DP[0] = 1;
for (int i=0;i < c.size(); i++)
for (int j = 0; j <= n - c[i];j++)
DP[j+c[i]] += DP[j];
return DP[n];
}
Почему работает это, думаю понятно. Теперь если мы хотим использовать меморизацию, это делается примерно так:
vector < long > c;
map< pair<int,int>,long> mem;
long getWays(long n, int p){
if (p >= c.size() || n < 0)
return 0;
if (n == 0)
return 1;
if (mem.count(make_pair(n,p)))
return mem[make_pair(n,p)];
return mem[make_pair(n,p)] = getWays(n-c[p],p) + getWays(n,p+1);
}
///
getWays(n, 0);
Учитывая ограничения задачи вместо пары <n,p>
можно (да и стоит на самом деле) хранить 1 число <n * 300 + p>
.
Но большого смысла в рекурсии я не вижу, ну не считая что она проще придумается. А ресурсов больше требует.
Оборудование для ресторана: новинки профессиональной кухонной техники
Частный дом престарелых в Киеве: комфорт, забота и профессиональный уход
Всем привет, у меня на Home View генерится список ссылок:
Не могу разобраться в вопросе имются ли технологии позволяющие написать аналог 2D игры "Age of empires 2" для браузера? (Строительство зданий в любом...
Всем доброй ночи/дняразбираюсь с google app script, и стоит перед мною задание: