finding minimum number in a integer - algorithm

Given an n-digit Number and a number 'k'. You have to remove ‘k’ digits from the number and give the shortest number from the remaining ‘n-k’ digits such that the sequence of digits remains same. For example, if the number is 637824 and k = 3. So you have to remove 3 digits from the given number. The number formed from the remaining digits should be the smallest possible and the sequence of digits must not be changed. So the output should be 324.
Approach which i have used same as inclusion exclusion logic:
Input 63119 and K=2:
Select 9 + minimum of(6311) = 19 or
don't select 9, select 1 + minimum of(631) = 11 and finally take minimum of all.
For input 4567813 and k=3:
Select 3 and 1 along with minimum of(45678) = 413
I am using recursion logic to get this right but i am not able to implement this with code and i am spent force now. I need help with this recursion. I am not after better solution.
#define min(a, b) ((a)>(b)?(b):(a));
int minimum(char *s, int i, int j)
{
if (i == j)
return s[i] - '0';
return min(s[j]-'0', minimum(s, i, j-1));
}
int add_up(char *s, int i, int j)
{
int sum = 0, mul = 1;
while(i < j) {
sum = sum + (s[j] - '0')*mul;
j--;mul *= 10;
}
return sum;
}
int foo(char *s, int size, int j, int k)
{
int sum = 0, i, mul = 1;
if (k < 0 || j > size || j < 0)
return 0;
if ((k == 0) && (j != 0))
return add_up(s, 0, j);
if ((k == 1) && (j != 0))
return minimum(s, 0, j);
if (k-1 == j)
return add_up(s, 0, j);
for (i=k;i>=0;i--) {
sum += min((s[j]-'0')+10*foo(s, size, j-1, k-1), foo(s, size, j-1, k));
}
return sum;
}
int main()
{
char s[] = {"4567813"};
printf("%d\n", foo(s, strlen(s)-1, strlen(s)-1, 2));
return 0;
}

You have said finally take minimum of all but you have taken minimum of all and then added them. You need to take minimum for each i and save minimum over all i in sum. See the code for clarification. Also there is bug in your add_up function, it should add until i<=j.
int add_up(char *s, int i, int j)
{
int sum=0, mul=1;
while(i <= j) { // modification here
sum=sum + (s[j] - '0')*mul;
j--; mul*=10;
}
return sum;
}
int foo(char *s, int size, int j, int k)
{
int sum=INT_MAX, i, mul=1;
if(k < 0 || j > size || j < 0)
return 0;
if((k == 0) && (j != 0))
return add_up(s, 0, j);
if((k == 1) && (j != 0))
return minimum(s, 0, j);
if(k-1 == j)
return add_up(s, 0, j);
for(i=k; i>=0; i--) {
int res=min((s[j]-'0')+10*foo(s, size, j-1, k-1), foo(s, size, j-1, k));
sum=min(sum,res); // minimum over all possible i
}
return sum;
}

Related

Top down approach 01 Matrix

I new do dynamic programming and I am attempting the following problem on leetcode: 01 Matrix
Problem: Given an m x n binary matrix mat, return the distance of the nearest 0 for each cell. The distance between two adjacent cells is 1.
I have attempted the problem using top-down dynamic programming but cannot seem to get the right answer for all the test cases. In all most all cases, the matrix is almost optimized except for a few values. My algorithm entails finding a '1' and then doing a depth first search in all 4 directions and then taking the minimum of the values + 1 and saving that to the memoization table (ans[][]).
I have tried to search for a top down approach but all most all the solutions are bottom up. Can anyone please help me understand why taking the minimum of the steps in all 4 directions using memoization doesn't not yield an optimal solution or what my solution is missing?
class Solution {
public int[][] updateMatrix(int[][] mat) {
int m = mat.length;
int n = mat[0].length;
int[][] ans = new int[m][n];
for(int i = 0; i <m; i++){
for(int j = 0; j <n; j++){
if(mat[i][j] == 0){
ans[i][j] = 0;
}
else{
ans[i][j] = -1;
}
}
}
for(int i = 0; i < m; i++){
for(int j = 0; j < n; j++){
if(ans[i][j] == - 1){
boolean[][] visited = new boolean[m][n];
ans[i][j] = dfs(i, j, m, n, mat, ans, visited);
}
}
}
for(int i = 0; i < m; i++){
for(int j = 0; j < n; j++){
boolean[][] visited = new boolean[m][n];
ans[i][j] = Math.min(ans[i][j], dfs(i, j, m, n, mat, ans, visited));
}
}
return ans;
}
public int dfs(int i, int j, int m, int n, int[][]mat, int[][] ans, boolean[][] visited){
if(i >= m || i < 0 || j >=n || j < 0|| visited[i][j]){
return Integer.MAX_VALUE;
}
if(mat[i][j] == 0){
return 0;
}
if(ans[i][j] != -1){
return ans[i][j];
}
visited[i][j] = true;
int up = dfs(i - 1, j, m, n, mat, ans, visited);
int down = dfs(i + 1, j, m, n, mat, ans, visited);
int left = dfs( i, j - 1, m, n, mat, ans, visited);
int right = dfs(i, j + 1, m, n, mat, ans,visited);
visited[i][j] = false;
ans[i][j] = Math.min (up, Math.min(down, Math.min(left, right))) + 1;
return ans[i][j];
}
}
The 3 double-loops at the beginning could be reduced to one double-loop, the 3rd one seems to be completely superfluous. Dfs is not working here. E.g. you will go 4 fields up 1 left and 4 fields down and save 9 but actually that field could be reached in 1 step to the left, you just ignore it because you already have a result. Even if you would fix the problems, this is still O((nm)^2) instead of O(nm). For an O(nm) solution you can initialize the result with 0 where you have a 0, with -1 where there is no 0 next to it and 1 where you have a 1 with a 0 next to it, additionally add the position of this 1 to a list. Initialize c to 2. Go through the list and check the positions up, left, right and down, if it is a -1 in the result replace it by c and add this position to a new list. Replace the list by the new list, increment c and go through the list again and again until it is empty.
There is also a working DFS implementation that is easier to understand:
https://leetcode.com/problems/01-matrix/discuss/732601/DFS-O(1)-Space
class Solution {
public int[][] updateMatrix(int[][] dist) {
int m = dist.length;
int n = dist[0].length;
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (dist[i][j] != 0) {
dist[i][j] = Integer.MAX_VALUE;
}
}
}
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (dist[i][j] == 0) {
dfs(dist, i - 1, j, 1);
dfs(dist, i + 1, j, 1);
dfs(dist, i, j - 1, 1);
dfs(dist, i, j + 1, 1);
}
}
}
return dist;
}
private void dfs(int[][] dist, int i, int j, int value) {
if (i >= 0 && i < dist.length && j >= 0 && j < dist[0].length && value < dist[i][j]) {
dist[i][j] = value;
dfs(dist, i - 1, j, value + 1);
dfs(dist, i + 1, j, value + 1);
dfs(dist, i, j - 1, value + 1);
dfs(dist, i, j + 1, value + 1);
}
}
}

Develop an algorithm

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;
}

Maximal Square with 0 inside

The question Maximal Square in https://leetcode.com/problems/maximal-square/description/ is easy to solve by DP. But how to solve the following up question:
Similar as Maximal Square question, but allows 0's inside a square, "inside" means the border of the square must be all 1.
For example, given the following matrix:
1 0 1 0 0
1 0 1 1 1
1 1 1 0 1
1 0 1 1 1
Return 9.
Update: Because the 3*3 matrix in the right bottom corner matches the requirement, the border must be all 1, and there can be 0 inside the square.
I thought up a O(n^3) algorithm: take maze[i][j] as the right bottom corner of the square if maze[i][j] == 1, enumerate the edge length of the square. If edge length is 3, consider whether maze[i - 2][j - 2], maze[i][j - 2], maze[i - 2][j], maze[i][j] forms a square with the numbers in each edge are all 1.
Is there any better algorithm?
Your problem can be solved in O (n * m) time and space complexity, where n is total rows and m is total columns in matrix. You may look at the code below where I have commented out to make it understandable.
Please, let me know if you have any doubt.
#include <bits/stdc++.h>
using namespace std;
void precalRowSum(vector< vector<int> >& grid, vector< vector<int> >&rowSum, int n, int m) {
// contiguous sum upto jth position in ith row
for (int i = 0; i < n; ++i) {
int sum = 0;
for (int j = 0; j < m; ++j) {
if (grid[i][j] == 1) {
sum++;
} else {
sum = 0;
}
rowSum[i][j] = sum;
}
}
}
void precalColSum(vector< vector<int> >& grid, vector< vector<int> >&colSum, int n, int m) {
// contiguous sum upto ith position in jth column
for (int j = 0; j < m; ++j) {
int sum = 0;
for (int i = 0; i < n; ++i) {
if (grid[i][j] == 1) {
sum++;
} else {
sum = 0;
}
colSum[i][j] = sum;
}
}
}
int solve(vector< vector<int> >& grid, int n, int m) {
vector< vector<int> >rowSum(n, vector<int>(m, 0));
vector< vector<int> >colSum(n, vector<int>(m, 0));
// calculate rowwise sum for 1
precalRowSum(grid, rowSum, n, m);
// calculate colwise sum for 1
precalColSum(grid, colSum, n, m);
vector< vector<int> >zerosHeight(n, vector<int>(m, 0));
int ans = 0;
for (int i = 0; i < (n - 1); ++i) {
for (int j = 0; j < m; ++j) {
zerosHeight[i][j] = ( grid[i][j] == 0 );
if (grid[i][j] == 0 && i > 0) {
zerosHeight[i][j] += zerosHeight[i - 1][j];
}
}
if (i == 0) continue;
// perform calculation on ith row
for (int j = 1; j < m; ) {
int height = zerosHeight[i][j];
if (!height) {
j++;
continue;
}
int cnt = 0;
while (j < m && height == zerosHeight[i][j]) {
j++;
cnt++;
}
if ( j == m) break;
if (cnt == height && (i - cnt) >= 0 ) {
// zeros are valid, now check validity for boundries
// Check validity of upper boundray, lower boundary, left boundary, right boundary respectively
if (rowSum[i - cnt][j] >= (cnt + 2) && rowSum[i + 1][j] >= (cnt + 2) &&
colSum[i + 1][j - cnt - 1] >= (cnt + 2) && colSum[i + 1][j] >= (cnt + 2) ){
ans = max(ans, (cnt + 2) * (cnt + 2) );
}
}
}
}
return ans;
}
int main() {
int n, m;
cin>>n>>m;
vector< vector<int> >grid;
for (int i = 0; i < n; ++i) {
vector<int>tmp;
for (int j = 0; j < m; ++j) {
int x;
cin>>x;
tmp.push_back(x);
}
grid.push_back(tmp);
}
cout<<endl;
cout<< solve(grid, n, m) <<endl;
return 0;
}

Number of heaps using n distinct integers- Time complexity

I am solving the problem to find the maximum number of max heaps that can be formed using n distinct integers (say 1..n). I have solved it using the following
recurrence with some help from this: https://www.quora.com/How-many-Binary-heaps-can-be-made-from-N-distinct-elements :
T(N) = N-1 (C) L * T(L) * T(R). where L is the number of nodes in the left subtree and R is the number of nodes in the right subtree. I have also implemented it in c++ using dynamic programming. But I am stuck in find the time complexity of it. Can someone help me with this?
#include <iostream>
using namespace std;
#define MAXN 105 //maximum value of n here
int dp[MAXN]; //dp[i] = number of max heaps for i distinct integers
int nck[MAXN][MAXN]; //nck[i][j] = number of ways to choose j elements form i elements, no order */
int log2[MAXN]; //log2[i] = floor of logarithm of base 2 of i
//to calculate nCk
int choose(int n, int k)
{
if (k > n)
return 0;
if (n <= 1)
return 1;
if (k == 0)
return 1;
if (nck[n][k] != -1)
return nck[n][k];
int answer = choose(n-1, k-1) + choose(n-1, k);
nck[n][k] = answer;
return answer;
}
//calculate l for give value of n
int getLeft(int n)
{
if (n == 1)
return 0;
int h = log2[n];
//max number of elements that can be present in the hth level of any heap
int numh = (1 << h); //(2 ^ h)
//number of elements that are actually present in last level(hth level)
//(2^h - 1)
int last = n - ((1 << h) - 1);
//if more than half-filled
if (last >= (numh / 2))
return (1 << h) - 1; // (2^h) - 1
else
return (1 << h) - 1 - ((numh / 2) - last);
}
//find maximum number of heaps for n
int numberOfHeaps(int n)
{
if (n <= 1)
return 1;
if (dp[n] != -1)
return dp[n];
int left = getLeft(n);
int ans = (choose(n-1, left) * numberOfHeaps(left)) * (numberOfHeaps(n-1-left));
dp[n] = ans;
return ans;
}
//function to intialize arrays
int solve(int n)
{
for (int i = 0; i <= n; i++)
dp[i] = -1;
for (int i = 0; i <= n; i++)
for (int j = 0; j <=n; j++)
nck[i][j] = -1;
int currLog2 = -1;
int currPower2 = 1;
//for each power of two find logarithm
for (int i = 1; i <= n; i++)
{
if (currPower2 == i)
{
currLog2++;
currPower2 *= 2;
}
log2[i] = currLog2;
}
return numberOfHeaps(n);
}
//driver function
int main()
{
int n=10;
cout << solve(n) << endl;
return 0;
}

Algorithm. How to find longest subsequence of integers in an array such that gcd of any two consecutive number in the sequence is greather than 1?

Given`en an array of integers. We have to find the length of the longest subsequence of integers such that gcd of any two consecutive elements in the sequence is greater than 1.
for ex: if array = [12, 8, 2, 3, 6, 9]
then one such subsequence can be = {12, 8, 2, 6, 9}
other one can be= {12, 3, 6, 9}
I tried to solve this problem by dynamic programming. Assume that maxCount is the array such that maxCount[i] will have the length of such longest subsequence
ending at index i.
`maxCount[0]=1 ;
for(i=1; i<N; i++)
{
max = 1 ;
for(j=i-1; j>=0; j--)
{
if(gcd(arr[i], arr[j]) > 1)
{
temp = maxCount[j] + 1 ;
if(temp > max)
max = temp ;
}
}
maxCount[i]=max;
}``
max = 0;
for(i=0; i<N; i++)
{
if(maxCount[i] > max)
max = maxCount[i] ;
}
cout<<max<<endl ;
`
But, this approach is getting timeout. As its time complexity is O(N^2). Can we improve the time complexity?
The condition "gcd is greater than 1" means that numbers have at least one common divisor. So, let dp[i] equals to the length of longest sequence finishing on a number divisible by i.
int n;
cin >> n;
const int MAX_NUM = 100 * 1000;
static int dp[MAX_NUM];
for(int i = 0; i < n; ++i)
{
int x;
cin >> x;
int cur = 1;
vector<int> d;
for(int i = 2; i * i <= x; ++i)
{
if(x % i == 0)
{
cur = max(cur, dp[i] + 1);
cur = max(cur, dp[x / i] + 1);
d.push_back(i);
d.push_back(x / i);
}
}
if(x > 1)
{
cur = max(cur, dp[x] + 1);
d.push_back(x);
}
for(int j : d)
{
dp[j] = cur;
}
}
cout << *max_element(dp, dp + MAX_NUM) << endl;
This solution has O(N * sqrt(MAX_NUM)) complexity. Actually you can calculate dp values only for prime numbers. To implement this you should be able to get prime factorization in less than O(N^0.5) time (this method, for example). That optimization should cast complexity to O(N * factorization + Nlog(N)). As memory optimization, you can replace dp array with map or unordered_map.
GCD takes log m time, where m is the maximum number in the array. Therefore, using a Segment Tree and binary search, one can reduce the time complexity to O(n log (m² * n)) (with O(n log m) preprocessing). This list details other data structures that can be used for RMQ-type queries and to reduce the complexity further.
Here is one possible implementation of this:
#include <bits/stdc++.h>
using namespace std;
struct SegTree {
using ftype = function<int(int, int)>;
vector<int> vec;
int l, og, dummy;
ftype f;
template<typename T> SegTree(const vector<T> &v, const T &x, const ftype &func) : og(v.size()), f(func), l(1), dummy(x) {
assert(og >= 1);
while (l < og) l *= 2;
vec = vector<int>(l*2);
for (int i = l; i < l+og; i++) vec[i] = v[i-l];
for (int i = l+og; i < 2*l; i++) vec[i] = dummy;
for (int i = l-1; i >= 1; i--) {
if (vec[2*i] == dummy && vec[2*i+1] == dummy) vec[i] = dummy;
else if (vec[2*i] == dummy) vec[i] = vec[2*i+1];
else if (vec[2*i+1] == dummy) vec[i] = vec[2*i];
else vec[i] = f(vec[2*i], vec[2*i+1]);
}
}
SegTree() {}
void valid(int x) {assert(x >= 0 && x < og);}
int get(int a, int b) {
valid(a); valid(b); assert(b >= a);
a += l; b += l;
int s = vec[a];
a++;
while (a <= b) {
if (a % 2 == 1) {
if (vec[a] != dummy) s = f(s, vec[a]);
a++;
}
if (b % 2 == 0) {
if (vec[b] != dummy) s = f(s, vec[b]);
b--;
}
a /= 2; b /= 2;
}
return s;
}
void add(int x, int c) {
valid(x);
x += l;
vec[x] += c;
for (x /= 2; x >= 1; x /= 2) {
if (vec[2*x] == dummy && vec[2*x+1] == dummy) vec[x] = dummy;
else if (vec[2*x] == dummy) vec[x] = vec[2*x+1];
else if (vec[2*x+1] == dummy) vec[x] = vec[2*x];
else vec[x] = f(vec[2*x], vec[2*x+1]);
}
}
void update(int x, int c) {add(x, c-vec[x+l]);}
};
// Constructor (where val is something that an element in the array is
// guaranteed to never reach):
// SegTree st(vec, val, func);
// finds longest subsequence where GCD is greater than 1
int longest(const vector<int> &vec) {
int l = vec.size();
SegTree st(vec, -1, [](int a, int b){return __gcd(a, b);});
// checks if a certain length is valid in O(n log (m² * n)) time
auto valid = [&](int n) -> bool {
for (int i = 0; i <= l-n; i++) {
if (st.get(i, i+n-1) != 1) {
return true;
}
}
return false;
};
int length = 0;
// do a "binary search" on the best possible length
for (int i = l; i >= 1; i /= 2) {
while (length+i <= l && valid(length+i)) {
length += i;
}
}
return length;
}

Resources