Has anyone tried to solve this particular problem? https://cses.fi/problemset/task/1189
Can someone help with an approach?
This works but doesn't optimize the steps
Tried recursion, but since the array 'a' needs to be updated, not sure how recursion can work in this case.
private int findMinSteps(int[] a, int[] b, int n) {
int cnt = 0;
do {
for(int i=1; i <= n; i++) {
if(a[i] == b[i]) continue;
if(a[i] > b[i]) { //we can give
if(a[left(i)] < b[left(i)]) { //give to left
a[i] -= 1;
a[left(i)] += 1;
cnt ++;
} else /*if(a[right(i)] < b[right(i)])*/ { //give to right
a[i] -= 1;
a[right(i)] += 1;
cnt ++;
}
} else { //we have to receive
if(a[left(i)] > b[left(i)]) { //receive from left`
a[i] += 1;
a[left(i)] -= 1;
cnt ++;
} else { //receive from right
a[i] += 1;
a[right(i)] -= 1;
cnt ++;
}
} //if-else
} //for
} while(!Arrays.equals(a, b));
return cnt;
} //findMinSteps
Here's a recursive solution that doesn't work either
private int findMinSteps(int[] a, int[] b, int n) {
/*if only one kid or zero kids are there, there is no mis-match
*because the total amount of food is correct
*/
//System.out.println(Arrays.toString(a));
//System.out.println(Arrays.toString(b));
if(n < 1)
return 0;
if(a[n] == b[n])
return findMinSteps(a, b, n-1);
if(a[n] > b[n]) {
//At each step a child can give 1 unit of food to neighbor
int l = left(n);
int r = right(n);
a[n] -= 1;
if(a[l] < b[l]) {
a[l] += 1;
} else if(a[r] < b[r]) {
a[r] += 1;
}
return 1+findMinSteps(a, b, n-1);
} else
return findMinSteps(a, b, n-1);
}
When I am passing this Input I am getting wrong answer
coin[] = {5,6}
Amount(W) = 10
my answer = 1
Correct Answer should be 2 i.e {5,5}
void coin_make(int W, vector<int> coin){
int n = coin.size();
int dp[n+1][W+1];
for(int i = 0; i <=W; i++){
dp[0][i] = INT_MAX;
}
for(int i = 1; i <= n; i++){
for(int j = 1; j <= W; j++){
if(coin[i-1] == j){
dp[i][j] = 1;
}
else if(coin[i-1] > j){
dp[i][j] = dp[i-1][j];
}
else {
dp[i][j] = min(dp[i-1][j],
1 + dp[i][j-coin[i-1]]);
}
}
}
cout<<dp[n][W];}
You're overflowing on dp[1][6], since you try to calculate 1 + INT_MAX. This error propagates further and finally the answer is not correct. When I ran it on my machine, I got -2147483648. You should use some other constant as "infinity" to prevent overflows (e.g. 2e9 (or -1, but this would require some additional if statements)). Then the code will work fine on your provided test case.
I participated in a programming competition at my University. I solved all the questions except this one. Now I am practicing this question to improve my skills. But I can't figure out the algorithm. If there is any algorithm existing please update me. Or any similar algorithm is present then please tell me I will change it according to this question.
This is what I want to do.
The First line of input is the distance between two points.
After that, each subsequent line contains a pair of numbers indicating the length of cable and quantity of that cable. These cables are used to join the two points.
Input is terminated by 0 0
Output:
The output should contain a single integer representing the minimum number of joints possible to build the requested length of cableway. If no solution possible than print "No solution".
Sample Input
444
16 2
3 2
2 2
30 3
50 10
45 12
8 12
0 0
Sample Output
10
Thanks guys. I found a solution from "Perfect subset Sum" problem and then made a few changes in it. Here's the code.
#include <bits/stdc++.h>
using namespace std;
bool dp[100][100];
int sizeOfJoints = -1;
void display(const vector<int>& v)
{
if (sizeOfJoints == -1)
{
sizeOfJoints = v.size() - 1;
}
else if (v.size()< sizeOfJoints)
{
sizeOfJoints = v.size() - 1;
}
}
// A recursive function to print all subsets with the
// help of dp[][]. Vector p[] stores current subset.
void printSubsetsRec(int arr[], int i, int sum, vector<int>& p)
{
// If sum becomes 0
if (sum == 0)
{
display(p);
return;
}
if(i<=0 || sum<0)
return;
// If given sum can be achieved after ignoring
// current element.
if (dp[i-1][sum])
{
// Create a new vector to store path
//vector<int> b = p;
printSubsetsRec(arr, i-1, sum, p);
}
// If given sum can be achieved after considering
// current element.
if (sum >= arr[i-1] && dp[i-1][sum-arr[i-1]])
{
p.push_back(arr[i-1]);
printSubsetsRec(arr, i-1, sum-arr[i-1], p);
p.pop_back();
}
}
// all subsets of arr[0..n-1] with sum 0.
void printAllSubsets(int arr[], int n, int sum)
{
if (n == 0 || sum < 0)
return;
// If sum is 0, then answer is true
for (int i = 0; i <= n; i++)
dp[i][0] = true;
// If sum is not 0 and set is empty, then answer is false
for (int i = 1; i <= sum; i++)
dp[0][i] = false;
// Fill the subset table in botton up manner
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= sum; j++)
{
if(j<arr[i-1])
dp[i][j] = dp[i-1][j];
if (j >= arr[i-1])
dp[i][j] = dp[i-1][j] ||
dp[i - 1][j-arr[i-1]];
}
}
if (dp[n][sum] == false)
{
return;
}
// Now recursively traverse dp[][] to find all
// paths from dp[n-1][sum]
vector<int> p;
printSubsetsRec(arr, n, sum, p);
}
// Driver code
int main()
{
int input[2000];
int inputIndex = 0;
int i = 0;
int distance = 0;
cout<< "Enter Input: " <<endl;
cin>> distance;
while(true)
{
int temp1 = 0;
int temp2 = 0;
cin>> temp1;
cin>> temp2;
if (temp1 == 0 && temp2 == 0)
{
break;
}
for (i = 0; i < temp2; i++)
input[inputIndex++] = temp1;
}
cout<< "Processing output. Please wait: " <<endl;
printAllSubsets(input, inputIndex, distance);
if(sizeOfJoints != -1)
cout<<sizeOfJoints;
else
cout<<"No Solution Possible";
return 0;
}
I have an array which is constituted of only 0s and 1s. Task is to find index of a 0, replacing which with a 1 results in the longest possible sequence of ones for the given array.
Solution has to work within O(n) time and O(1) space.
Eg:
Array - 011101101001
Answer - 4 ( that produces 011111101001)
My Approach gives me a result better than O(n2) but times out on long string inputs.
int findIndex(int[] a){
int maxlength = 0; int maxIndex= -1;
int n=a.length;
int i=0;
while(true){
if( a[i] == 0 ){
int leftLenght=0;
int j=i-1;
//finding count of 1s to left of this zero
while(j>=0){
if(a[j]!=1){
break;
}
leftLenght++;
j--;
}
int rightLenght=0;
j=i+1;
// finding count of 1s to right of this zero
while(j<n){
if(a[j]!=1){
break;
}
rightLenght++;
j++;
}
if(maxlength < leftLenght+rightLenght + 1){
maxlength = leftLenght+rightLenght + 1;
maxIndex = i;
}
}
if(i == n-1){
break;
}
i++;
}
return maxIndex;
}
The approach is simple, you just need to maintain two numbers while iterating through the array, the current count of the continuous block of one, and the last continuous block of one, which separated by zero.
Note: this solution assumes that there will be at least one zero in the array, otherwise, it will return -1
int cal(int[]data){
int last = 0;
int cur = 0;
int max = 0;
int start = -1;
int index = -1;
for(int i = 0; i < data.length; i++){
if(data[i] == 0){
if(max < 1 + last + cur){
max = 1 + last + cur;
if(start != -1){
index = start;
}else{
index = i;
}
}
last = cur;
start = i;
cur = 0;
}else{
cur++;
}
}
if(cur != 0 && start != -1){
if(max < 1 + last + cur){
return start;
}
}
return index;
}
O(n) time, O(1) space
Live demo: https://ideone.com/1hjS25
I believe the problem can we solved by just maintaining a variable which stores the last trails of 1's that we saw before reaching a '0'.
int last_trail = 0;
int cur_trail = 0;
int last_seen = -1;
int ans = 0, maxVal = 0;
for(int i = 0; i < a.size(); i++) {
if(a[i] == '0') {
if(cur_trail + last_trail + 1 > maxVal) {
maxVal = cur_trail + last_trail + 1;
ans = last_seen;
}
last_trail = cur_trail;
cur_trail = 0;
last_seen = i;
} else {
cur_trail++;
}
}
if(cur_trail + last_trail + 1 > maxVal && last_seen > -1) {
maxVal = cur_trail + last_trail + 1;
ans = last_seen;
}
This can be solved by a technique that is known as two pointers. Most two-pointers use O(1) space and O(n) time.
Code : https://www.ideone.com/N8bznU
#include <iostream>
#include <string>
using namespace std;
int findOptimal(string &s) {
s += '0'; // add a sentinel 0
int best_zero = -1;
int prev_zero = -1;
int zeros_in_interval = 0;
int start = 0;
int best_answer = -1;
for(int i = 0; i < (int)s.length(); ++i) {
if(s[i] == '1') continue;
else if(s[i] == '0' and zeros_in_interval == 0) {
zeros_in_interval++;
prev_zero = i;
}
else if(s[i] == '0' and zeros_in_interval == 1) {
int curr_answer = i - start; // [start, i) only contains one 0
cout << "tried this : [" << s.substr(start, i - start) << "]\n";
if(curr_answer > best_answer) {
best_answer = curr_answer;
best_zero = prev_zero;
}
start = prev_zero + 1;
prev_zero = i;
}
}
cout << "Answer = " << best_zero << endl;
return best_zero;
}
int main() {
string input = "011101101001";
findOptimal(input);
return 0;
}
This is an implementation in C++. The output looks like this:
tried this : [0111]
tried this : [111011]
tried this : [1101]
tried this : [10]
tried this : [01]
Answer = 4
I have worked on this problem for days but still, couldn't figure out a way to solve it. My solution can't solve some edge cases.
Problem:
Given an array and sorted in ascending order, rotate the array by k elements, find the index of the minimum number of the array(first element of the original non-rotated array).For example:
1. Give {3,4,1,3,3}, return 2.
2. Give {3,3,3,3,3}, return 0.
3. Give {1,1,4,1,1,1}, return 3.
Without duplicates, this problem can be solved in O(logn) time using binary search, with duplicates a modified binary search can be used, worst case time complexity is O(n).
My code:
public int FindPivot(int[] array)
{
var i = 0;
var j = array.Length - 1;
while (i < j)
{
var mid = i + (j - i) / 2 + 1;
if (array[mid] < array[array.Length - 1])
{
j = mid - 1;
}
else if (array[mid] > array[array.Length - 1])
{
i = mid;
}
else
{
if (array[mid] == array[j])
{
j--;
}
if (array[mid] == array[i])
{
i++;
}
}
}
return i+1;
}
It doesn't work if the input is {3,3,1,3,3,3,3,3}, it returns 3 while the correct answer is 2. Because at the last step is i points to index 2 and j moves from index 3 to index 2, it gets the correct element but i+1 makes the result wrong.What am I missing here?
I have modified your code as below and it seems works for all cases.
I cannot think of any good way to handle all the corner cases, because your original code kind of mix up the concept of the algorithm without duplicate elements (divide into two sub arrays) and two-pointers algorithm when there is duplicate elements.
I would say the problem is that the else case which is moving the two pointers did not cover all cases, like there are chances that you will go into else block with array[i] < array[mid]
Therefore I just modified it using newbie's method: Add two variables to keep track the minimum element and minimum index we found. Update it whenever the pointers move to cover all the cases possible. Return the index at the end. You cannot do something like return i+1 as it won't handle case for k = 0 which is no rotation at all ( {1,2,3,4})
The modified code is written in C# which I guess from your sample code.
PS: Though in average, this is faster than O(N) if the data is partially sorted without duplicate elements, it's worst case is still O(N) as you mentioned. So if I were you, I would just do a simple iteration and find the first minimum element...
Also from this reference, O(N) is the optimal you can reach if there are duplicate elements.
http://ideone.com/v3KVwu
using System;
public class Test
{
public static int FindPivot(int[] array)
{
var i = 0;
var j = array.Length - 1;
var ans = 1<<20;
var idx = 1<<20;
while (i < j)
{
var mid = i + (j - i) / 2 + 1;
// Console.WriteLine(String.Format("{0}, {1}, {2}", i, mid, j));
if (array[mid] < array[array.Length - 1])
{
if(array[mid] < ans || (array[mid] == ans && mid < idx)) { ans = array[mid]; idx = mid;}
j = mid - 1;
}
else if (array[mid] > array[array.Length - 1])
{
i = mid;
}
else
{
// Here did not consider case if array[i] < mid
if(array[j] < ans || (array[j] == ans && j < idx)) { ans = array[j]; idx = j;}
if(array[i] < ans || (array[i] == ans && i < idx)) { ans = array[i]; idx = i;}
if (array[mid] == array[j])
{
j--;
}
if (array[mid] == array[i])
{
i++;
}
}
}
if(array[j] < ans || (array[j] == ans && j < idx)) { ans = array[j]; idx = j;}
if(array[i] < ans || (array[i] == ans && i < idx)) { ans = array[i]; idx = i;}
Console.WriteLine("Minimum = " + ans);
return idx;
}
public static void Main()
{
int []a = {7,7,7,7,8,8,9,9,1,2,2,2,7,7};
int []b = {3,3,1,3,3,3,3,3};
int []c = {1,2,3,4};
int []d = {4,4,4,4};
int []e = {3,3,3,3,3,3,3,1,3};
int []f = {4,5,6,7,1,1,1,1};
Console.WriteLine(FindPivot(a));
Console.WriteLine(FindPivot(b));
Console.WriteLine(FindPivot(c));
Console.WriteLine(FindPivot(d));
Console.WriteLine(FindPivot(e));
Console.WriteLine(FindPivot(f));
}
}
Based on #shole's answer, I modified the code a little bit to cover cases like {1,1,1,1,3,1,1,1,1,1,1,1,1}.
public int FindPivot(int[] nums)
{
var i = 0;
var j = nums.Length - 1;
var ans = int.MaxValue;
var idx = int.MaxValue;
while (i < j)
{
var mid = i + (j - i) / 2 + 1;
if (nums[mid] < nums[nums.Length - 1])
{
if (nums[mid] < ans || (nums[mid] == ans && mid < idx)) { ans = nums[mid]; idx = mid; }
j = mid - 1;
}
else if (nums[mid] > nums[nums.Length - 1])
{
i = mid;
}
else
{
if (nums[j] < ans || (nums[j] == ans && j < idx)) { ans = nums[j]; idx = j; }
if (nums[mid] == nums[j])
{
j--;
}
if (nums[mid] == nums[i])
{
i++;
}
}
}
// Deal with cases like {1,1,1,1,1}
if (nums[i] == nums[nums.Length - 1] && nums[i] == nums[0] && i == j)
{
return 0;
}
if (nums[j] < ans || (nums[j] == ans && j < idx)) { ans = nums[j]; idx = j; }
return idx;
}