#include <iostream>
#include <string>
if (__cplusplus == 202101L)
<< std::string("C++23");
std::cout else if (__cplusplus == 202002L)
<< std::string("C++20");
std::cout else if (__cplusplus == 201703L)
<< std::string("C++17");
std::cout else if (__cplusplus == 201402L)
<< std::string("C++14");
std::cout else if (__cplusplus == 201103L)
<< std::string("C++11");
std::cout else if (__cplusplus == 199711L)
<< std::string("C++98");
std::cout else
<< std::string("pre-standard C++.") << std::to_string(__cplusplus);
std::cout
<< std::string("\n"); std::cout
Leet Code #2472
2472: Painting the Walls
Getting some more practice in, with more targetted prep to come.
Iteration One
Goals
- Get a first working solution without looking at answers
- Implement a >50% runtime solution
#include <deque>
#include <iterator>
#include <iostream>
#include <string>
#include <algorithm>
// ---- COPY FROM HERE ----
class Solution {
public:/**
* @pre size of cost == size of time
*/
int paintWalls(std::vector<int>& cost, std::vector<int>& time) {
// The greedy approach:
// - Sort pairs by cost, then time
// - Pop pairs off list for paid painter
// - Grab walls for free painter from other end
// https://stackoverflow.com/questions/18478385/convert-two-vectors-of-int-with-the-same-length-into-one-vector-of-pairs-of-int
<std::pair<int, int>> priorities;
std::vector
std::transform(cost.begin(), cost.end(), time.begin(), std::back_inserter(priorities),int cost, int time) { return std::make_pair(cost, time); });
[] (
for (auto iter = priorities.begin(); iter != priorities.end(); ++iter)
{<< (*iter).first << ", " << (*iter).second << std::endl << std::flush;
std::cout
}
std::sort(priorities.begin(), priorities.end(), &left, auto &right)
[] (auto
{// Want to do lowest cost, and then lowest time
// if (left.first < right.first)
// return true;
// else if (left.first == right.first && left.second < right.second )
// return true;
// else
// return false;
// Cost per hour
if ((left.first / left.second) < (right.first / right.second))
return true;
// Equal cost per hour, then go with lesser cost
else if ((left.first / left.second) == (right.first / right.second) && left.first < right.first )
return true;
else
return false;
;
})
for (auto iter = priorities.begin(); iter != priorities.end(); ++iter)
{<< (*iter).first << ", " << (*iter).second << std::endl << std::flush;
std::cout
}
int tmp_time = -1;
int total_cost = 0;
<std::pair<int,int>> work_deque(priorities.size());
std::deque;
std::move(begin(priorities), end(priorities), back_inserter(work_deque))
while (!work_deque.empty())
{// Paid Worker
= work_deque.front();
std::pair paid_job ;
work_deque.pop_front()= paid_job.second;
tmp_time += paid_job.first;
total_cost
// Free Worker
while (tmp_time > 0 && !work_deque.empty()) {
// If there are only two jobs left and only get one for free
if (work_deque.size() == 2 && tmp_time == 1)
{ = work_deque.front();
std::pair front ;
work_deque.pop_front()= work_deque.back();
std::pair back ;
work_deque.pop_back()
+= std::min(front.first, back.first);
total_cost
}else
{;
work_deque.pop_back()--;
tmp_time
}
}
}
return total_cost;
};
}
// ---- COPY FROM HERE ----
;
Solution tmp<int> cost1;
std::vector= { 1,2,3,2 };
cost1 <int> time1;
std::vector= { 1,2,3,2 };
time1 <int> cost2;
std::vector= { 2,3,4,2 };
cost2 <int> time2;
std::vector= { 1,1,1,1 };
time2 <int> cost3;
std::vector= { 26,53,10,24,25,20,63,51 };
cost3 <int> time3;
std::vector= { 1, 1, 1, 1, 2, 2, 2, 1 };
time3 <int> cost4;
std::vector= { 8,7,5,15 };
cost4 <int> time4;
std::vector= { 1,1,2,1 };
time4 <int> cost5;
std::vector= { 42,8,28,35,21,13,21,35 };
cost5 <int> time5;
std::vector= { 2,1,1,1,2,1,1,2 };
time5 <int> cost6;
std::vector= { 76,25,96,46,85,19,29,88,2,5 };
cost6 <int> time6;
std::vector= { 1,2,1,3,1,3,3,3,2,1 };
time6
<< "Expected: 3 Generated: \n" << tmp.paintWalls(cost1,time1) << std::endl << std::flush;
std::cout << "Expected: 4 Generated: \n" << tmp.paintWalls(cost2,time2) << std::endl << std::flush;
std::cout << "Expected: 55 Generated: \n" << tmp.paintWalls(cost3,time3) << std::endl << std::flush;
std::cout << "Expected: 12 Generated: \n" << tmp.paintWalls(cost4,time4) << std::endl << std::flush;
std::cout << "Expected: 63 Generated: \n" << tmp.paintWalls(cost5,time5) << std::endl << std::flush;
std::cout << "Expected: 46 Generated: \n" << tmp.paintWalls(cost6,time6) << std::endl << std::flush; std::cout
%%timeit
;
Solution tmp<int> cost1;
std::vector= { 1,2,3,2 };
cost1 <int> time1;
std::vector= { 1,2,3,2 };
time1
;
tmp.paintWalls(cost1,time1); tmp.paintWalls(cost2,time2)
Results
We will have to wait and see how our internal timings compare to leetCode runtime analysis
- I started to look at a solution here, as the algorithm was proving to not be workable with my simple approach.
- 1812 / 2557 testcases passed: clearly there are edge cases where my algorithm doesn’t look to build a true solution, and makes greedy (incorrect) choices
- My min cost/hour did help improve the amount of test cases that pass
Iteration Two
Goals
- Implement DP in order to solve all test cases
Reference Solution
https://leetcode.com/problems/painting-the-walls/solutions/4166467/not-hard-video-solution-dynamic-programming-explained-easy-to-understand/
class Solution {
public:int paintWalls(int[] cost, int[] time) {
int n = cost.length;
int[] money = new int[n+1];
int)1e9);
Arrays.fill(money,(0]=0;
money[for(int i=0;i<n;i++)
{for(int j=n;j>0;j--)
{=Math.min(money[j],money[Math.max(j-time[i]-1,0)]+cost[i]);
money[j]
}
}return money[n];
} }
#include <vector>
#include <algorithm>
class Solution {
public:/**
* @pre size of cost == size of time
*/
int paintWalls(std::vector<int>& cost, std::vector<int>& time) {
<int> cost_per_wall(cost.size() + 1, 1e9);
std::vector0] = 0;
cost_per_wall[
// Loop forward over walls, determining cost as we go
for(int i = 0; i < cost.size(); i++)
{// Loop backwards from the end of the list
// Start with trying to paint all walls in remaining time
for(int j = cost.size(); j > 0; j--)
{//
int x = j - time[i] - 1;
int tmp = std::max(x, 0);
// if tmp == 0, we ~can~ paint all remaining walls
int tmp2 = cost_per_wall[tmp];
// if tmp == 0, then tmp2 == 0
int curr_wall_cost = cost[i];
int curr_try_max = cost_per_wall[j];
int tmp4 = std::min(curr_try_max, tmp2 + curr_wall_cost);
// if we can paint all reamining walls with time, tmp2 == 0 and we take curr_wall_cost
// Otherwise tmp = num_remaining_walls, tmp2 = best_guess_for_cost_to_paint_num_remaining,
// min (cost of painting this wall, best_guess + current_wall's cost)
// As we build the solution dynamically, this should get us the best solution
= tmp4;
cost_per_wall[j]
}
}return cost_per_wall[cost.size()];
}; }
#include <vector>
#include <algorithm>
class Solution {
public:/**
* @pre size of cost == size of time
*/
int paintWalls(std::vector<int>& cost, std::vector<int>& time) {
<int> cost_per_wall(cost.size() + 1, 1e9);
std::vector0] = 0;
cost_per_wall[
for(int i = 0; i < cost.size(); i++)
{for(int j = cost.size(); j > 0; j--)
{= std::min(cost_per_wall[j], cost_per_wall[std::max(j - time[i] - 1, 0)] + cost[i]);
cost_per_wall[j]
}
}return cost_per_wall[cost.size()];
}; }
I decided to leave it here, and taking a pening coding interview. Maybe look forward to more of this to come, but C++ proves difficult to do in this execution environment, and I think the Python side of things is the more interesting use-case for this, so will be the focus moving forward. Cool mini-series?