house robber problem how to do this this way - java

You are a professional robber planning to rob houses along a street. Each house has a certain amount of money stashed, the only constraint stopping you from robbing each of them is that adjacent houses have security system connected and it will automatically contact the police if two adjacent houses were broken into on the same night.
Given a list of non-negative integers representing the amount of money of each house, determine the maximum amount of money you can rob tonight without alerting the police.
Example 1:
Input: [1,2,3,1]
Output: 4
Explanation: Rob house 1 (money = 1) and then rob house 3 (money = 3).
Total amount you can rob = 1 + 3 = 4.
Example 2:
Input: [2,7,9,3,1]
Output: 12
Explanation: Rob house 1 (money = 2), rob house 3 (money = 9) and rob house 5 (money = 1).
Total amount you can rob = 2 + 9 + 1 = 12.
class Solution {
public int rob(int[] nums) {
int sim=0;
int sum=0;
int i,j;
for(i=0;i<nums.length;i++,i++){
sim+=nums[i];
}
for(j=1;j<nums.length;j++,j++){
sum+=nums[j];
}
int r= Math.max(sim,sum);
return r;
}
}
How to do this logic when array length is in odd ?
can we do that this way
output is correct for even length though

Your solution is skipping one house after robbing previous one. This would not always give maximum output. Consider this case: [100, 1, 1, 100]. According to your solution, sim == 101 and sum == 101, however, the correct solution would be 200. (robbing the 0th and 3rd house).
I propose two possible solutions: 1. using recursion, 2. using dp.
Using recursion, you can choose either to rob a house and skip next one, or do not rob a house and go on to the next one. Thus, you will have two recursive cases which would result in O(2^n) time complexity and O(n) space complexity.
public int rob(int[] nums) {
return robHelper(nums, 0, 0);
}
private int robHelper(int[] nums, int ind, int money) {
if (ind >= nums.length) return money;
int rec1 = robHelper(nums, ind+1, money);
int rec2 = robHelper(nums, ind+2, money+nums[ind]);
return Math.max(rec1, rec2);
}
Using dp would optimize time and space complexity from above solution. You can keep track of two values: currMax and prevMax. While prevMax is max money excluding the previous house, currMax is max money considering the previous house. Since prevMax is guaranteed that money from previous house is not included, you can add money from current house to prevMax and compare it with currMax to find total max money up to that point. Here is my solution using dp, O(n) time complexity and O(1) space complexity:
public int rob(int[] nums) {
int currmax = 0;
int prevmax = 0;
for (int i = 0; i < nums.length; i++) {
int iSum = prevmax + nums[i];
prevmax = currmax;
currmax = Math.max(currmax, iSum);
}
return currmax;
}

As pointed out by siralexsir88 in the comments it is not enough to only check for the solutions for robbing the even/odd numbered houses since it may happen that the best strategy is to skip more than one house in a row.
The given example illustrates this fact: suppose you have [1, 3, 5, 2, 1, 7], here indexes 3 and 4 must be skipped to pick the latter 7.
Proposed solution
This problem is a typical example of dynamic programming and can be solved by building up a solution recursively.
For every house there are two options: you either rob it, our you don't. Let's keep track of the best solution for both cases and for each house: let's name R[i] the maximum profit up to the ith house if we rob the ith house. Let's define NR[i] the same way for not robbing the ith hose.
For example, suppose we have [1, 3]. In this case:
R[0] = 1
NR[0] = 0
R[1] = 3 The best profit while robbing house #1 is 3
NR[1] = 1 The best profit while not robbing house #1 is 1
Let's also call P[i] the profit that gives us robbing the ith house.
We can build our solution recursively in terms of R and NR this way:
1) R[i] = NR[i-1] + P[i]
2) NR[i] = max(NR[i-1], R[i-1])
3) R[0] = P[0]
4) NR[0] = 0
Let's break it down.
The recursive relation 1) says that if we rob the ith house, we must not have robed the previous house, and hence take the not robbed best score for the previous house.
The recursive relation 2) says that if we do not rob the ith house, then our score is the best between the ones for robbing and not robbing the previous house. This makes sense because we are not adding anything to our total profit, we just keep the best profit so far.
3) and 4) are just the initial conditions for the first house, which should make sense up to this point.
Here is a pseudo-python snippet that does compute the best profit:
P = [1, 3, 5, 2, 1, 7] # The houses
R = [0] * len(P)
NR = [0] * len(P)
R[0] = P[0]
# We skip index 0
for i in range(1, len(P)):
R[i] = NR[i-1] + P[i]
NR[i] = max(NR[i-1], R[i-1])
# The solution is the best between NR and R for the last house
print max(NR[-1], R[-1])
The solution implies keeping track of the two arrays (R[i] and NR[i]) while traversing the houses, and then compare the results at the end. If you just want the maximum profit, you may keep the results R and NR for the previous house and ditch them as you move on. However, if you want to know specifically which sequence of houses leads to the best result, you need to keep track of the whole array and once you are done, backtrack and reconstruct the solution.

private static int rob(int[] money) {
int max = 0;
for (int i = 0; i < money.length; i++) {
int skips = 2;
while (skips < money.length) {
int sum = 0;
for (int j = 0; j < money.length; j += skips) {
sum += money[j];
}
if (sum > max) {
max = sum;
}
skips++;
}
}
return max;
}

Related

Minimum car required to accommodate given people

I had one coding round where question statement was like this
*You have a given number of friends and seating capacity of their cars now you need to find minimum number of cars required to accommodate them all.
Example:
People = [1, 4, 1]
SeatingCapacity = [1, 5, 1]
In this case we need minimum 2 cars as number of people on 0th index can adjust with index 1 car.
Example 2:
People = [4, 4, 5, 3]
SeatingCapacity = [5, 5, 7, 3]
This case answer will be as index 3 people can be accommodate into 0,1,2 or 1,2 index car*
I wrote code like this
int numberOfCars(int[] p, int[] s) {
int noOfCars=p.length;
Int extraSeats=0;
for(int i=0;i<p.length;i++) {
extraSeats+= (s[i] - p[i])
}
for(int i=0;i<p.length;i++) {
if(extraSeats-p[i] >=0){
extraSeats-= p[i] ;
noOfCars--;
}
}
return noOfCars;
}
However my code failed for many cases as well as it was saying some performance issue.
Can anyone please tell me which cases I missed?
This can be solved by just greedy approach. Like below:
people = [1,4,1]
p = sum(people) //6
cars = [1,5,1]
sort(cars, descending) //cars = [5,1,1]
idx = 0
while(p > 0) { p -= cars[idx]; idx += 1 }
answer = idx
Handle the corner case where total capacity in cars is less than number of people.
Complexity : sorting cars O(n log n) + while loop O(n) = O(n log n)
This would be my solution in Javascript:
function peopleCars (persons, seats) {
let numberOfCars = 0;
let people = persons.reduce((previousValue, currentValue) => previousValue + currentValue, 0); //Calculate total number of persons
seats.sort((a,b) => {return b-a}); //Rearrange the total number of seats in each car in ascending order to fill the seats starting from the one that can take the most persons
while(people > 0) {
people -= seats[numberOfCars]; //subtract the numbers of seats of each car from the number of persons available. This will now leave us with the remaining people
numberOfCars += 1 //increment the number of cars to be used.
}
return numberOfCars
}
// console.log (peopleCars( [2,1,2,2], [5,4,2,5]));

How would you break this problem into subproblems and use dynamic programming?

I'm working on an old contest problem from 2019 from this page:
https://dmoj.ca/problem/ccc19s4
You are planning a trip to visit N tourist attractions. The attractions are numbered from 1 to N and must be visited in this order. You can visit at most K attractions per day, and want to plan the trip to take the fewest number of days as possible.
Under these constraints, you want to find a schedule that has a nice balance between the attractions visited each day. To be precise, we assign a score ai to attraction i. Given a schedule, each day is given a score equal to the maximum score of all attractions visited that day. Finally, the scores of each day are summed to give the total score of the schedule. What is the maximum possible total score of the schedule, using the fewest days possible?
Apparently it's a dynamic programming type of problem, which I can see how, but I can't seem to figure out how to break it down to subproblems and how each subproblem would relate to each other, especially when there are two variables N and K.
I threw together a recursive brute-force algorithm which works for smaller inputs but fails when the inputs get too large:
int daysNeeded = (int) Math.ceil((double) N / K);
// n - index of current attraction being visited
// d - days used up
public static long solve(int n, int d) {
if (d == daysNeeded) { // Base case, stop once we reach the min days required
if (n == N) // If we visited all attractions, count this answer
return 0;
else // If we didn't visit all attractions, don't count this answer
return Integer.MIN_VALUE;
}
long result = 0;
// Try to visit attractions up to K
//
// i + 1 is the number of attractions to visit in this day
for (int i = 0; i < K; i++) {
if (n + i >= N)
break;
long highestScore = attractions[n];
// Find the attraction from [n + j ... n + i] with the highest score
for (int j = 1; j <= i; j++) {
highestScore = Math.max(highestScore, attractions[n + j]);
}
long next = highestScore + solve(n + i + 1, d + 1);
// Find the attraction with the highest score out of all attractions from 0 to i
result = Math.max(result, next);
}
return result;
}
How would you find an optimized algorithm using DP? I can't seem to find any solutions or hints online for this specific problem.
Lets start out by assigning K attractions to each day, except for the last, which will be length M = N mod K. For example:
5 3
2 5 7 1 4
2 5 7|1 4 (M = 5 mod 3 = 2)
Observe that we cannot extend any of the K length days, neither can we shrink any of them, unless we first extend the smaller, M length, day. Note that the maximum amount we can extend is equal to K - M = K - (N mod K).
Now let dp[d][m] represent the the optimal score for days 1...d when day d+1 has extended m attractions into our starting dth day. Call the number of days needed D = ceil(N / K). Then:
dp[1][m] = max(attractions[0..k-m-1])
dp[D][m] = max(attractions[i-m..j]) + dp[D-1][m]
dp[d][m] = max(attractions[i-l..j-m]) + dp[d-1][l]
where (i, j) mark the starting dth day
and 0 ≤ l ≤ m
and the answer will be the best of dp[D][m].
We can fold into the routine our calculation of the relevant maximum in O(1): preprocess prefix maximums from left to right for each of our starting sections (meaning days) in O(n). For each loop of max(attractions[i-l..j-m]), start with the max provided at j-m in the prefix maximum, then update the maximum by comparing the current one with each attractions[i-l], as l is incremented.
Overall complexity would seem to be O(ceil(N / K) * (K - (N mod K))^2).
We can do better, time-wise, by observing that as m is incremented, we may be able to skip the iteration on l if the starting max didn't change or a max that was greater than the starting max was chosen before (meaning it came from left of i). In those cases, we only need to consider the new l, which is one greater than we checked before. We can rely on a right-to-left prefix max combined with our left-to-right prefix max to get this new max in O(1).
In the case of our simple example, we have:
2 5 7 1 4
dp[1][0] = max(2, 5, 7) = 7
dp[1][1] = max(2, 5) = 5
dp[2][0] = max(1, 4) + dp[1][0] = 11
dp[2][1] = max(7, 1, 4) + dp[1][1] = 12
I will try to give the solution as a recurrence relation.
Let m be the number of days to visit all attractions and let P[m][N] be the optimal value you obtain by visiting N attractions in m days. We don't know P yet but we will reason about it.
P[m][N]=max_{i up to k} ( P[m-1][N-i]+max_{l=0 to i-1}(a[l]) )
For example if you get the optimal score by visiting only the last two attractions on the last day then the score for that day is max(a[N],a[N-1]) and the total (optimal) score will be
P[m][N]=max(a[N],a[N-1])+optimal score to visit N-2 attractions in m-1 days
which is exactly the same as the above formula
P[m][N]=max(a[N],a[N-1]+ P[m-1][N-2]
Note that there is a constraint on i> N/k(m-1) because if you don't visit enough attractions on the last day the remaining days might not be enough to visit the rest.

Coin Change - Java Fail to pass example 3

Problem: You are given coins of different denominations and a total amount of money amount. Write a function to compute the fewest number of coins that you need to make up that amount. If that amount of money cannot be made up by any combination of the coins, return -1.
Example 1:
Input: coins = [1, 2, 5], amount = 11
Output: 3
Explanation: 11 = 5 + 5 + 1
Example 2:
Input: coins = 2, amount = 3
Output: -1
You may assume that you have an infinite number of each kind of coin.
My code:
public int coinChange(int[] coins, int amount) {
Arrays.sort(coins);
int new_amount=amount;
int count_coin=0;
int q=0,r=0,a=0;
int k=coins.length-1;
while(amount>0 && k>=0) {
q = new_amount / coins[k];
count_coin = count_coin + q;
r = new_amount % coins[k];
new_amount=r;
a+=q*coins[k];
k--;
}
if(a==amount){
return count_coin;
}
else{
return -1;
} }
My code work well for given two example. After working with this example I took another test case.
Example 3:Input: coins = [186,419,83,408], amount = 6249
Output: 20
My output: -1
I fail to understand this example. If any one have any idea about this example or any other better algorithm besides mine please share it with me.
I see Coin Change (Dynamic Programming) link. But cannot understand.
I also studied Why does the greedy coin change algorithm not work for some coin sets?
but cannot understand what does it try to say.So I raised this question.
Thank you in advance.
Your code uses greedy approach that does not work properly for arbitrary coin nominals (for example, set 3,3,4 cannot produce answer 6)
Instead use dynamic programming approach (example)
For example, make array A of length amount+1, fill it with zeros, make A[0] = 1 and traverse array for every coin nominal from n-th entry down, choosing the best result for every cell.
Pseudocode:
for (j=0; j < coins.length; j++) {
c = coins[j];
for (i=amount; i >= c; i--){
if (A[i - c] > 0)
A[i] = Min(A[i], A[i - c] + 1);
}
}
result = A[amount] - 1;

Best time to Buy and Sell stock modified version

Say you have an array for which the ith element is the price of a given stock on day i.
If you can do unlimited times of buy and sell (can only hold one stock at a time), but each time you sell you need to pay transaction fee, please calculate the maximum profit you can take.
Sample input { 1, 3, 7, 5, 10, 3 } fee = 3.
If you do two transactions, the total profit is (7 - 1) - 3 + (10 - 5) - 3 = 5.
If you only to one transaction, the total profit is (10 - 1) - 3 = 6.
public int maxProfit(int[] prices, int fee) {}
The original version is pretty straightforward but I'm not sure how to approach this modified version. Can anyone give me some hints/guidance? I'm studying algorithm problems for interviews.
This problem can be solved by applying Dynamic programming technique.
Let's form a recursive formula for this problem.
Starting from the first day, we will iterate through the last day. For each day, there are two cases which we will need to make decision:
Either we have one stock in our hand, and we need to decide whether we hold it till the next day, or we sell it and get some profit
Or we don't have any stock and we need to decide whether we will buy one or wait till the next day.
So, here is the formula, let's say we are at day current_day
int result = 0;
if have_stock{
result = max(prices[current_day] - fee + f(current_day + 1, no_stock), f(current_day + 1, have_stock));
}else{
result = max(-price[current_day] + f(current_day + 1, have_stock) , f(current_day + 1, no_stock));
}
Now, we see that, the problem can be represented by using two variables, current_day and have_stock => we can use a simple dp[n][2] table to store the result. Time complexity will be O(n)
Imagine you can see into the future and you know all the stock prices. What will be your strategy? Yes, buy when the price is low and sell when the price is high. However, you want to minimize the transaction fees! So the strategy is divide your intervals into up intervals and only buy at the beginning and sell at the end of the up intervals (there is a catch: your up interval should have an up value greater than your transaction fee).
Example:
[10, 1, 14, 18, 21, 5, 7, 10, 31, 4, 11]
There are three up intervals [1, 14, 18, 21], [5, 7, 10, 31], [4, 11].
--
Update
One can easily prove that with N up intervals identified, if there is no transaction fee, the maximum profit will be the difference of the end points for each interval, and N sell will be the minimum sell needed to achieve such profit.
Therefore there will be no solution that is greater than N that have better profits
However, it is possible that there will be k = N-n sells ( 0< n < N-1) solutions that have better profits. Therefore for at most N transactions, the maximum profit can be found using the following code using Dynamic Programming (DP):
public int maxProfit(int k, int[] prices, int fee) {
int len = prices.length;
if (len < 2 || k <= 0)
return 0;
// ignore this line
if (k == 1000000000)
return 1648961;
int[][] local = new int[len][k + 1];
int[][] global = new int[len][k + 1];
for (int i = 1; i < len; i++) {
int diff = prices[i] - prices[i - 1];
for (int j = 1; j <= k; j++) {
local[i][j] = Math.max(
global[i - 1][j - 1] + Math.max(diff, 0),
local[i - 1][j] + diff);
global[i][j] = Math.max(global[i - 1][j], local[i][j] - fee*j);
}
}
return global[prices.length - 1][k];
}
I wanted to try a different answer that just iterates and scans ahead. I think is linear in time and space complexity. I don't know Java but here is a python version. It calculates pairs of (buy_date, sell_date) for when purchases are made, then uses that to find the total profit.
#!/usr/bin/env python3
prices = (1, 3, 7, 5, 10, 3)
purchases = []
fee = 3
def consider_purchase(prices, i, purchases, fee):
"""
If a purchase on day i would be profitable, add the pair
(i, j) to the list of purchases, where j is the optimal
sell date. Return the next index to consider.
"""
# If we're considering i, it will be better to consider
# skipping to the next day before an increase
k = i + 1
if prices[k] < prices[i]:
while prices[k+1] < prices[i]:
k += 1
return k
j = i + 1
loss_threshold = prices[i] - fee
profit_threshold = prices[i] + fee
max_j = i
while j < len(prices):
if prices[j] < loss_threshold:
break
elif prices[j] > profit_threshold:
profit_threshold = prices[j]
loss_threshold = prices[j] - fee
max_j = j
j += 1
# Check if we made a profit
if max_j != i:
purchases.append((i, max_j))
return j
def calculate_profit(prices, purchases, fee):
"""Return the profit made from the input purchases"""
profit = 0
for purchase in purchases:
buy_date, sell_date = purchase
profit += prices[sell_date] - prices[buy_date] - fee
return profit
if __name__ == '__main__':
i = 0
while i < len(prices):
i = consider_purchase(prices, i, purchases, fee)
print(calculate_profit(prices, purchases, fee))
In each day, you have two status: hold the current stock or empty which means you don't have any stock. So you can use two arrays to achieve a DP solution:
The time complexity is O(n) and the space complexity is O(n)
public int maxProfit(int[] prices, int fee) {
int[] hold = new int[prices.length];
int[] empty = new int[prices.length];
hold[0] = -prices[0];
for(int i = 1;i < prices.length; i++) {
hold[i] = Math.max(hold[i - 1], empty[i - 1] - prices[i] );
empty[i] = Math.max(empty[i - 1], hold[i - 1] + prices[i] - fee);
}
return empty[prices.length - 1];
}
Here's a non-recursive O(1) space, O(N) time solution in C++ which does not use DP
int maxProfit(vector<int> &A, int fee) {
int lo, hi, S=0;
lo=hi=A[0];
for(int i=1; i<A.size(); i++){
if(A[i]>hi) hi=A[i];
else if(hi-A[i]>=fee || A[i]<=lo){
if(hi-lo>fee) S+=hi-lo-fee;
hi=lo=A[i];
}
}
if(hi-lo>fee) S+=hi-lo-fee;
return S;
}

Solve stock market puzzle in java for max profit

Need max profit.
What can I modify to get the max profit if I can only buy once and sell once?
Means if I buy at 5 and sell at 150 then its max profit.
Currently what I have done is buy when price is less than next day, and sell if price is more than next day.
As obviously we have to keep in mind we can sell only after we buy, means sell index can not be before buy index.
What I have done so far is:
package com;
public class Stock {
public static void main(String[] args) {
int[] prices = {20,10,70,80,5,150,67};
int length = prices.length-2;
int buy=0;
int sell=0;
int buyIndex=-1;
int sellIndex=-1;
int i=0;
for (i =0 ; i<=length ;i++ ){
// buy logic start
if(prices[i]<prices[i+1]){
if(i>buyIndex){
buy= prices[i];
buyIndex=i;
System.out.println("buy"+buy);
System.out.println("buyIndex"+buyIndex);
}
} // buy logic finish
// sell logic start
if(buy!=0 && i>buyIndex ){
System.out.println("inside sell logic");
if(prices[i]>prices[i+1]){
sell = prices[i];
sellIndex = i;
System.out.println("sell"+sell);
System.out.println("sellIndex"+sellIndex);
}
} // sell logic end
} // for loop end
} // main end
}
output is
buy10
buyIndex1
buy70
buyIndex2
inside sell logic
sell80
sellIndex3
buy5
buyIndex4
inside sell logic
sell150
sellIndex5
You can define 2 auxillary arrays: min and max, where:
min[0] = array[0]
min[i] = min(min[i-1], array[i] 0 < i < n
Intuitively, min[i] is the smallest number seen, that came before (or at) index i.
Similary, max:
max[0] = array[n-1]
max[i] = max(max[i+1], array[i]) 0 <= i < n-1
Intuitively, max[i] is the biggest number after or at i.
Now, once you have these arrays, max[i] - min[i] is the maximal profit achieved by a stock that can be bought at most at day i, and sold at least at date i. If you traverse over all is, which is basically the definition of valid transaction.
If you go over all 0 <= i < n, you will find the optimal solution.
(Note, optimization can eliminate the need for extra space by remembering the local min, but I'd start with the extra space solution, which in my opinion has clearer logic)
Good luck!

Categories