DP memoized approach for Longest common substring - algorithm
can anyone provide the memoized approach for longest common substring between two strings.I know the bottom solution but I am not able to think in top-down manner.
Expected time complexity-O(n^2)
TOP-DOWN APPROACH
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
string X, Y; //input strings
int ans, dp[105][105]; // ans : answer
int LCS(int n, int m) //our function return value of (n,m) state
{ // so that we can use the result in (n+1,m+1) state
if(n == 0 || m == 0) return 0; //in case of match in (n+1,m+1) state
if(dp[n][m] != -1) return dp[n][m];
LCS(n-1,m); //to visit all n*m states (try example: X:ASDF
LCS(n,m-1); // we call these states first Y:ASDFF)
if(X[n-1] == Y[m-1])
{
dp[n][m] = LCS(n-1,m-1) + 1;
ans = max(ans, dp[n][m]);
return dp[n][m];
}
return dp[n][m] = 0;
}
int main()
{
int t; cin>>t;
while(t--)
{
int n, m; cin>>n>>m; //length of strings
cin>>X>>Y;
memset(dp, -1, sizeof dp);
ans = 0;
LCS(n, m);
cout<<ans<<'\n';
}
return 0;
}
Memoization with recursion works with top-down approach.
Taking LCS example using DP from Cormen into consideration below is the pseudo code describing how it will work.
MEMOIZED-LCS-LENGTH(X,Y)
m<-length[X]
n<-length[Y]
for(i<-1 to m)
do for(j<-1 to n)
c[i,j]<- -1
for(i<-1 to m)
c[i,0]<-0
for(j<-1 to n)
c[0,j]<-0
return RECURSIVE-LCS-LENGTH(X,Y,1,1)
RECURSIVE-LCS-LENGTH(X,Y,i,j)
if(c[i,j]!=-1)
return c[i,j]
//Above 2 line fetches the result if already present, instead of computing it again.
if(x[i]==y[j])
then c[i,j]<-RECURSIVE-LCS-LENGTH(X,Y,i+1,j+1)+1
else
c1<- RECURSIVE-LCS-LENGTH(X,Y,i+1,j)
c2<-RECURSIVE-LCS-LENGTH(X,Y,i,j+1)
if(c1<c2)
then c[i,j]<-c1
else c[i,j]<-c2
return c[i,j]
Java Solution:
class Solution {
public int findLength(int[] A, int[] B) {
int[][] cache = new int[A.length][B.length];
Arrays.stream(cache).forEach(a->Arrays.fill(a,-1));
int[] res = new int[1];
findLength(0, 0, A, B, cache, res);
return res[0];
}
public static int findLength(int a, int b, int[] A, int[] B, int[][] cache, int[] res){
if( a >= A.length || b >= B.length )
return 0;
if(cache[a][b] != -1){
return cache[a][b];
}
if(A[a] == B[b]){
cache[a][b] = 1 + findLength(a+1,b+1,A,B,cache,res);
// remember you can not return here: why? see case: s1 = 1,2,3 s2=1,4,1,2,3
}
// try out other possiblities and update cache
findLength(a+1,b,A,B,cache,res);
findLength(a,b+1,A,B,cache,res);
//you can avoid this and find max value at end in cache
res[0] = Math.max(res[0],cache[a][b]);
//at this point cache might have -1 or updated value, if its -1 make it to 0 as this location is visited and no common substring is there from here
cache[a][b] = Math.max(0,cache[a][b]);
return cache[a][b];
}
}
Recursion plus memoization in python. Please note this code is partially accepted on Hackerearth and Geeksforgeeks.For larger test cases, it is giving MLE.
import sys
sys.setrecursionlimit(1000000)
maxlen=0
t=None
def solve(s1, s2, n, m):
global maxlen, t
if n<=0 or m<=0:
return 0
if t[n][m]!=-1:
return t[n][m]
if s1[n-1]==s2[m-1]:
temp=1+solve(s1, s2, n-1, m-1)
maxlen=max(maxlen, temp)
t[n][m]=temp
return temp
t[n][m]=0
return 0
class Solution:
def longestCommonSubstr(self, S1, S2, n, m):
global maxlen, t
maxlen=0
t=[[-1]*(m+1) for i in range(n+1)]
for i in range(n+1):
for j in range(m+1):
solve(S1, S2, i, j)
return maxlen
if __name__=='__main__':
S1=input().strip()
S2=input().strip()
n=len(S1)
m=len(S2)
ob = Solution()
print(ob.longestCommonSubstr(S1, S2, n, m))
An easy solution is described below. Here memo[n][m] does not store the length of
greatest substring but you can store the greatest substring in pointer maxi as follows:
#include<iostream>
#include<string>
using namespace std;
int lcs(string X,string Y,int n,int m,int *maxi,int memo[][8]) {
if(n==0||m==0) {
return 0;
}
int k=0;
int j=0;
if(memo[n-1][m-1]!=-1) {
return memo[n-1][m-1];
}
if(X[n-1]==Y[m-1]) {
memo[n-1][m-1] = 1+lcs(X,Y,n-1,m-1,maxi,memo);
if(*maxi<memo[n-1][m-1])
*maxi=memo[n-1][m-1];
}
else {
memo[n-1][m-1]=0;
}
int l = lcs(X,Y,n-1,m,maxi,memo);
int i = lcs(X,Y,n,m-1,maxi,memo);
return memo[n-1][m-1];
}
int main()
{
int n,m;
string X = "abcdxyze";
//string X = "abcd";
string Y = "xyzabcde";
n=X.length();
m=Y.length();
int memo[n][8];
for(int i=0;i<n;i++) {
for(int j=0;j<m;j++) {
memo[i][j]=-1;
}
}
int maxi=0;
int k = lcs(X,Y,n,m,&maxi,memo);
cout << maxi;
return 0;
}
class Solution {
public:
int t[1005][1005];
int maxC = 0;
int recur_memo(vector<int>& nums1, vector<int>& nums2, int m, int n) {
if(t[m][n] != -1)
return t[m][n];
if(m == 0 || n == 0)
return 0;
int max_substring_ending_here = 0;
//Example : "abcdezf" "abcdelf"
//You see that wowww, string1[m-1] = string2[n-1] = 'f' and you happily
go for (m-1, n-1)
//But you see, in future after a gap of 'l' and 'z', you will find
"abcde" and "abcde"
if(nums1[m-1] == nums2[n-1]) {
max_substring_ending_here = 1 + recur_memo(nums1, nums2, m-1, n-1);
}
//May be you find better results if you do (m-1, n) and you end up
updating maxC with some LAAARGEST COMMON SUBSTRING LENGTH
int decrease_m = recur_memo(nums1, nums2, m-1, n); //stage (m-1, n)
//OR,
//May be you find better results if you do (m, n-1) and you end up
updating maxC with some LAAARGEST COMMON SUBSTRING LENGTH
int decrease_n = recur_memo(nums1, nums2, m, n-1); //stage (m, n-1)
//Like I said, you need to keep on finding the maxC in every call you
make throughout your journey.
maxC = max({maxC, max_substring_ending_here, decrease_m, decrease_n});
//BUT BUT BUT, you need to return the best you found at this stage (m, n)
return t[m][n] = max_substring_ending_here;
}
int findLength(vector<int>& nums1, vector<int>& nums2) {
int m = nums1.size();
int n = nums2.size();
memset(t, -1, sizeof(t));
recur_memo(nums1, nums2, m, n); //resurive+memoization
return maxC;
}
};
Link : https://leetcode.com/problems/maximum-length-of-repeated-subarray/discuss/1169215/(1)-Recursive%2BMemo-(2)-Bottom-Up-(C%2B%2B)
Here is a recursive and top-down approach:
public int lcsSubstr(char[] s1, char[] s2, int m, int n, int c) {
if (m == 0 || n == 0) {
return c;
}
if (s1[m-1] == s2[n-1]) {
c = lcsSubstr(s1, s2, m-1, n-1, c+1);
} else {
c2 = Math.max(lcsSubstr(s1, s2, m, n - 1, 0), lcsSubstr(s1, s2, m-1, n, 0));
}
return Math.max(c, c2);
}
public int lcsSubstrMemo(char[] s1, char[] s2, int m, int n, int c, int[][] t) {
if(m == 0 || n == 0) {
return c;
}
if (t[m-1][n-1] != -1) return t[m-1][n-1];
if(s1[m - 1] == s2[n - 1]) {
c = lcsSubstr(s1, s2, m - 1, n - 1, c + 1);
} else {
c2 = Math.max(lcsSubstr(s1, s2, m, n - 1, 0), lcsSubstr(s1, s2, m - 1, n, 0));
}
t[m - 1][n - 1] = Math.max(c, c2);
return t[m-1][n-1];
}
Memoization refers to caching the solutions to subproblems in order to use them later. In the longest common subsequence problem, you try to match substrings of two subsequences to see if they match, maintaining in memory the longest one yet found. Here is the solution in Java you are looking for (memoized version of LCS):
public class LongestCommonSubsequence {
private static HashMap<Container, Integer> cache = new HashMap<>();
private static int count=0, total=0;
public static void main(String sargs[]){
Scanner scanner = new Scanner(System.in);
String x=scanner.nextLine();
String y=scanner.nextLine();
int max=0;
String longest="";
for(int j=0;j<x.length();j++){
String common=commonSubsequence(j,0, x, y);
if(max<common.length()){
max=common.length();
longest=common;
}
}
for(int j=0;j<y.length();j++){
String common=commonSubsequence(j,0, y, x);
if(max<common.length()){
max=common.length();
longest=common;
}
}
System.out.println(longest);
System.out.println("cache used "+count+" / "+total);
}
public static String commonSubsequence(final int startPositionX, int startPositionY, String x, String y){
StringBuilder commonSubsequence= new StringBuilder();
for(int i=startPositionX;i<x.length();i++){
Integer index=find(x.charAt(i),startPositionY,y);
if(index!=null){
commonSubsequence.append(x.charAt(i));
if(index!=y.length()-1)
startPositionY=index+1;
else
break;
}
}
return commonSubsequence.toString();
}
public static Integer find(char query, int startIndex, String target){
Integer pos=cache.get(new Container(query, startIndex));
total++;
if(pos!=null){
count++;
return pos;
}else{
for(int i=startIndex;i<target.length();i++){
if(target.charAt(i)==query){
cache.put(new Container(query, startIndex), i);
return i;
}
}
return null;
}
}
}
class Container{
private Character toMatch;
private Integer indexToStartMatch;
public Container(char t, int i){
toMatch=t;
indexToStartMatch=i;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime
* result
+ ((indexToStartMatch == null) ? 0 : indexToStartMatch
.hashCode());
result = prime * result + ((toMatch == null) ? 0 : toMatch.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Container other = (Container) obj;
if (indexToStartMatch == null) {
if (other.indexToStartMatch != null)
return false;
} else if (!indexToStartMatch.equals(other.indexToStartMatch))
return false;
if (toMatch == null) {
if (other.toMatch != null)
return false;
} else if (!toMatch.equals(other.toMatch))
return false;
return true;
}
}
Related
Looking for a data structure to perform range element update efficiently
I currently have the following data structure: class DataStructure { public: DataStructure(int n) : m_data(n, 0) { } void update(int i, int j, int value) { for (int k = i; k <= j; ++k) { m_data[k] = max(m_data[k], value); } } void reset(int i) { m_data[i] = 0; } int query(int i) { return m_data[i]; } private: vector<int> m_data; }; So what it does is rather simple: Initially there is a vector of n integers initialised to zero. update(i, j, value) updates the elements in the range [i, j] to be the max of the given value and their respective current value. The given value is in the range of [0, n]. reset(i) resets the value at index i to 0. query(i) returns the value at index i. I need to perform n updates, n resets and n query operations. Currently this code takes O(n*n) time, due to the update operation being O(n) in general. I am wondering if there are some smart ways to improve this to O(n*log n) time (or better) for n updates, n resets and n query operations, while maintaining O(n) space complexity?
Thanks for #qwertman for the explanation here is an algorithm that should work #include <iostream> #include <cstdio> using namespace std; #define max(a, b) (a>b?a:b) int tree[100005], lazy[100005]; void init(int idx, int l, int r){ if(l>r) return ; if(l==r){ tree[idx] = 0; lazy[idx] = -1; } else { tree[idx] = 0; lazy[idx] = -1; int mid = (l+r)/2; init(2*idx, l, mid); init(2*idx+1, mid+1, r); } } // l and r is for internal use the range a-b has to be updated void update(int idx, int l, int r, int a, int b, int val, bool isReset){ if(l>r || b<l || a>r){ return; } // printf("idx=%d l=%d r=%d a=%d b=%d val=%d\n",idx,l,r,a,b,val); if(lazy[idx] != -1){ tree[idx] = max(tree[idx], lazy[idx]); lazy[2*idx] = max(lazy[2*idx], lazy[idx]); lazy[2*idx+1] = max(lazy[2*idx+1], lazy[idx]); lazy[idx] = -1; } if(l>=a && r<=b){ // printf("updating\n"); tree[idx] = max(tree[idx], val); if(isReset){ tree[idx] = val; } lazy[2*idx] = max(lazy[2*idx], val); lazy[2*idx+1] = max(lazy[2*idx+1], val); lazy[idx] = -1; } else { int mid = (l+r)/2; update(2*idx, l, mid, a, b, val, isReset); update(2*idx+1, mid+1, r, a, b, val, isReset); tree[idx] = max(tree[2*idx], tree[2*idx+1]); } } int query(int idx, int l, int r, int a){ if(l>r || a<l || a>r){ return -1; } // printf("idx=%d l=%d r=%d a=%d\n",idx,l,r,a); if(lazy[idx] != -1){ tree[idx] = max(tree[idx], lazy[idx]); lazy[2*idx] = max(lazy[2*idx], lazy[idx]); lazy[2*idx+1] = max(lazy[2*idx+1], lazy[idx]); lazy[idx] = -1; } if(l==a && r==a){ // printf("----l=%d r=%d a=%d tree=%d\n",l,r,a,tree[idx]); return tree[idx]; } else { int mid = (l+r)/2; int left = query(2*idx, l, mid, a); int right = query(2*idx+1, mid+1, r, a); return max(left, right); } } int main() { // initializing everything to 0 init(1, 1, 10); // updating range 1-4 with value 7 update(1, 1, 10, 1, 4, 7, false); // query for 3 should result in 7 cout << query(1, 1, 10, 3) << endl; // updating 3-3 with value 9 update(1, 1, 10, 3, 3, 9, false); // should give 9 cout << query(1, 1, 10, 3) << endl; // isReset is set to true, so the function will do a hard reset update(1, 1, 10, 3, 3, 0, true); // should give 0 cout << query(1, 1, 10, 3) << endl; return 0; } you can run this code at http://ideone.com/Mkp4dQ some useful links for learning segment tree with lazy propagation hackerearth Geeksforgeeks
How to add memoization in subset sum?
I am trying to solve subset sum problem with recursive solution, but to make to make it a bit more efficient I am trying to put memoization in it. However the code without memoization gives correct solution but with memoization it doesn't work properly. public int subsetSum(int num[], int idx, int expecedSum, int dp[]) { if (expecedSum == 0) { return 1; } else if (idx < 0 || expecedSum < 0) { return 0; } else { if (dp[expecedSum] == -1) { int x = subsetSum(num, idx - 1, expecedSum, dp); int y = subsetSum(num, idx - 1, expecedSum - num[idx], dp); dp[expecedSum] = (x == 1 || y == 1) ? 1 : 0; } return dp[expecedSum]; } } public static void main(String args[]) { Solution s = new Solution(); int num[] = new int[]{1, 2, 3, 4, 5, 6, 7}; int sum = 0; int n = new Scanner(System.in).nextInt(); int dp[] = new int[n + 1]; for (int i = 0; i < dp.length; i++) { dp[i] = -1; } dp[0] = 1; s.subsetSum(num, num.length - 1, n, dp); } Can someone help me with why this is not working? If I enter n = 14 then ideally dp[14] should contains 1 but it doesn't contain 1.
The sum is not sufficient to describe the state. The pair (sum, index) is. If you make dp an array of arrays of size (max_sum + 1) x num.length and apply memoization for a pair (idx, expectedSum) in the subsetSet method, it works.
It has been years but this may help someone today. The idea is to take both the state - means once with including current element into the sum and once excluding current element into the sum. and then taking OR(||) for those values and store in the cache. the code will look something like this - #include <iostream> #include <vector> using namespace std; bool sumExists(vector<int> & a, int cursum, int n, vector<vector<int>> &dp) { if(n==0 && cursum != 0) return 0; if(cursum==0) return 1; if(dp[n][cursum] != -1) { return dp[n][cursum]; } int newsum = cursum - a[n-1]; bool returnval = false; if(newsum>=0) { dp[n][newsum] = sumExists(a, newsum, n-1, dp); dp[n][cursum] = sumExists(a, cursum, n-1, dp); returnval = dp[n][newsum] || dp[n][cursum]; } else { dp[n][cursum] = sumExists(a, cursum, n-1, dp); returnval = dp[n][cursum]; } return returnval; } int main() { // your code goes here vector<int> a{2,0,7,8,10}; int n = a.size(); int sum = 11; vector<vector<int>> dp(n+1, vector<int>(sum+1, -1)); for(int i=0;i<=n;++i) { dp[i][0]=true; } for(int i=1;i<=sum;++i) { dp[0][i]=false; } if(sumExists(a, sum, n, dp)) { cout<<"YES"<<endl; } else { cout<<"NO"<<endl; } }
Algorithm for Adding/Subtracting numbers to find if number can be made?
I was wondering if there is an efficient premade algorithm for determining if the sum/difference of a group of numbers can equal a different number. Example: 5, 8, 10, 2, using + or -, to equal 9. 5 - 8 = -3 + 10 = 7 + 2 = 9 If there is a preexisting algorithm, what is it called. If not, I can figure out how to program it, though it may not be efficient. Thank you!
Yeah, this is basically knapsack problem, but it can be computed in pseudopolynomial time using dynamic programming. I did it few month ago, so maybe this java code can help you, if you want to implement it : public void solve() { while (this.isEnd() == false) { int priceSum = this.getItemsInstance().getTotalPrice()/divide; int numOfItems = this.getItemsInstance().itemCount(); int maxWeight = this.getItemsInstance().getMaxWeight(); int[][] array = new int[numOfItems + 1][priceSum + 1]; boolean[][] arrayCounted = new boolean[numOfItems + 1][priceSum + 1]; for (int i = 0; i < numOfItems + 1; i++) { array[i][0] = 0; arrayCounted[i][0] = true; } int max = 0; int price = 0; for (int j = 1; j < priceSum + 1; j++) { for (int i = 1; i < numOfItems + 1; i++) { int temp = W(i, j, array, arrayCounted); if (temp <= maxWeight) { max = temp; price = j; } } } } } private int W(int i, int c, int[][] array, boolean[][] arrayCounted) { if (c < 0) { return MAX_PRICE / divide; } if (i == 0) { if (c == 0) { return 0; } else { return MAX_PRICE / divide; } } if (arrayCounted[i][c]) { return array[i][c]; } arrayCounted[i][c] = true; array[i][c] = Math.min(W(i - 1, c, array, arrayCounted), W(i - 1, c - this.items[i - 1].price/divide, array, arrayCounted) + this.items[i - 1].weight); return array[i][c]; }
its not an NP problem, if the problem is to find a given number from adding or subtracting each elements of a list/array. if you think about AP. here is a sample code in C++ int Np( int mn, list<int>a, int c ) { int size = a.size(), rst = 0, maxI = 0; std::list<int>::iterator it; while( size > c ) { a.sort(); maxI += a.back(); a.pop_back(); rst = 0; for( auto ele : a ) { rst += ele; cout << rst << endl; } if( (rst - maxI) == mn or (maxI - rst) == mn or (maxI + rst) == mn ) { return mn; } size--; } return rst; } this should help. i think.
I actually wrote a simple java program, I was not actually aware of knapsack strategies. This is my own solution. Hope this helps import java.util.ArrayList; import java.util.List; public class Puzzle { public static void main(String[] args) { int targetNumber = 0; int min = 2147483647; int[] numbers = {-10, -30, -20, -50}; //int[] numbers = {0,0,0,0}; //int[] numbers = {7, 2, 10}; //int[] numbers = {1, 2, 3, 4, 5}; //int[] numbers = {1000, 2, 3, 4, 100}; char set[] = {'+', '-'}; min = getNumberClosestToTarget(numbers, set, min, targetNumber); System.out.println(String.format(" %d is closest to %d", min, targetNumber)); } private static int getNumberClosestToTarget(int[] numbers, char[] set, int min, int targetNumber) { List<String> operators = new ArrayList<>(); computeAllOperatorsCombination(set, "", set.length, numbers.length - 1, operators); for (String operatorString : operators) { String[] ops = operatorString.split(""); int sum = computeSum(numbers, ops, numbers.length - 1); min = getClosestToTarget(min, targetNumber, sum); } return min; } static int computeSum(int[] numbers, String[] operators, int index) { int result = numbers[index]; if (index == 0) { return result; } else { switch (operators[index - 1]) { case "+": return computeSum(numbers, operators, index - 1) + result; case "-": return computeSum(numbers, operators, index - 1) - result; } return result; } } static void computeAllOperatorsCombination(char set[], String prefix, int n, int k, List<String> result) { if (k == 0) { result.add(prefix); return; } for (int i = 0; i < n; i++) { String newPrefix; newPrefix = prefix + set[i]; computeAllOperatorsCombination(set, newPrefix, n, k - 1, result); } } private static int getClosestToTarget(int min, int targetNumber, int r) { int distance = Math.abs(targetNumber - r) < Math.abs(r - targetNumber) ? Math.abs(targetNumber - r) : Math.abs(r - targetNumber); if (distance < Math.abs(min)) { min = distance; if (r < 0) { min = -distance; } } return min; } }
what is the fastest way to find the gcd of n numbers?
what is the fastest way to compute the greatest common divisor of n numbers?
Without recursion: int result = numbers[0]; for(int i = 1; i < numbers.length; i++){ result = gcd(result, numbers[i]); } return result; For very large arrays, it might be faster to use the fork-join pattern, where you split your array and calculate gcds in parallel. Here is some pseudocode: int calculateGCD(int[] numbers){ if(numbers.length <= 2){ return gcd(numbers); } else { INVOKE-IN-PARALLEL { left = calculateGCD(extractLeftHalf(numbers)); right = calculateGCD(extractRightHalf(numbers)); } return gcd(left,right); } }
You may want to sort the numbers first and compute the gcd recursively starting from the smallest two numbers.
C++17 I have written this function for calculating gcd of n numbers by using C++'s inbuilt __gcd(int a, int b) function. int gcd(vector<int> vec, int vsize) { int gcd = vec[0]; for (int i = 1; i < vsize; i++) { gcd = __gcd(gcd, vec[i]); } return gcd; } To know more about this function visit this link . Also refer to Dijkstra's GCD algorithm from the following link. It works without division. So it could be slightly faster (Please correct me if I am wrong.)
You should use Lehmer's GCD algorithm.
How about the following using Euclidean algorithm by subtraction: function getGCD(arr){ let min = Math.min(...arr); let max= Math.max(...arr); if(min==max){ return min; }else{ for(let i in arr){ if(arr[i]>min){ arr[i]=arr[i]-min; } } return getGCD(arr); } } console.log(getGCD([2,3,4,5,6])) The above implementation takes O(n^2) time. There are improvements that can be implemented but I didn't get around trying these out for n numbers.
If you have a lot of small numbers, factorization may be actually faster. //Java int[] array = {60, 90, 45}; int gcd = 1; outer: for (int d = 2; true; d += 1 + (d % 2)) { boolean any = false; do { boolean all = true; any = false; boolean ready = true; for (int i = 0; i < array.length; i++) { ready &= (array[i] == 1); if (array[i] % d == 0) { any = true; array[i] /= d; } else all = false; } if (all) gcd *= d; if (ready) break outer; } while (any); } System.out.println(gcd); (works for some examples, but not really tested)
Use the Euclidean algorithm : function gcd(a, b) while b ≠ 0 t := b; b := a mod b; a := t; return a; You apply it for the first two numbers, then the result with the third number, etc... : read(a); read(b); result := gcd(a, b); i := 3; while(i <= n){ read(a) result := gcd(result, a); } print(result);
Here below is the source code of the C program to find HCF of N numbers using Arrays. #include<stdio.h> int main() { int n,i,gcd; printf("Enter how many no.s u want to find gcd : "); scanf("%d",&n); int arr[n]; printf("\nEnter your numbers below :- \n "); for(i=0;i<n;i++) { printf("\nEnter your %d number = ",i+1); scanf("%d",&arr[i]); } gcd=arr[0]; int j=1; while(j<n) { if(arr[j]%gcd==0) { j++; } else { gcd=arr[j]%gcd; i++; } } printf("\nGCD of k no.s = %d ",gcd); return 0; } For more refer to this website for further clarification.......
You can use divide and conquer. To calculate gcdN([]), you divide the list into first half and second half. if it only has one num for each list. you calculate using gcd2(n1, n2). I just wrote a quick sample code. (assuming all num in the list are positive Ints) def gcdN(nums): n = len(nums) if n == 0: return "ERROR" if n == 1: return nums[0] if n >= 2: return gcd2(gcdN(nums[:n//2]), gcdN(nums[n//2:])) def gcd2(n1, n2): for num in xrange(min(n1, n2), 0, -1): if n1 % num == 0 and n2 % num == 0: return num
Here's a gcd method that uses the property that gcd(a, b, c) = gcd(a, gcd(b, c)). It uses BigInteger's gcd method since it is already optimized. public static BigInteger gcd(BigInteger[] parts){ BigInteger gcd = parts[0]; for(int i = 1; i < parts.length; i++) gcd = parts[i].gcd(gcd); return gcd; }
//Recursive solution to get the GCD of Two Numbers long long int gcd(long long int a,long long int b)<br> { return b==0 ? a : gcd(b,a%b); } int main(){ long long int a,b; cin>>a>>b; if(a>b) cout<<gcd(a,b); else cout<<gcd(b,a); return 0; }
import java.io.*; import java.util.*; import java.text.*; import java.math.*; import java.util.regex.*; class GCDArray{ public static int [] extractLeftHalf(int [] numbers) { int l =numbers.length/2; int arr[] = Arrays.copyOf(numbers, l+1); return arr; } public static int [] extractRightHalf(int [] numbers) { int l =numbers.length/2; int arr[] = Arrays.copyOfRange(numbers,l+1, numbers.length); return arr; } public static int gcd(int[] numbers) { if(numbers.length==1) return numbers[0]; else { int x = numbers[0]; int y = numbers[1]; while(y%x!=0) { int rem = y%x; y = x; x = rem; } return x; } } public static int gcd(int x,int y) { while(y%x!=0) { int rem = y%x; y = x; x = rem; } return x; } public static int calculateGCD(int[] numbers){ if(numbers.length <= 2){ return gcd(numbers); } else { int left = calculateGCD(extractLeftHalf(numbers)); int right = calculateGCD(extractRightHalf(numbers)); return gcd(left,right); } } public static void main(String[] args) { Scanner sc = new Scanner(System.in); int n = sc.nextInt(); int arr[] = new int[n]; for(int i=0;i<n;i++){ arr[i]=sc.nextInt(); } System.out.println(calculateGCD(arr)); } } ** Above is the java working code ..... the pseudo code of which is already mention by https://stackoverflow.com/users/7412/dogbane **
A recursive JavaScript (ES6) one-liner for any number of digits. const gcd = (a, b, ...c) => b ? gcd(b, a % b, ...c) : c.length ? gcd(a, ...c) : Math.abs(a);
This is what comes off the top of my head in Javascript. function calculateGCD(arrSize, arr) { if(!arrSize) return 0; var n = Math.min(...arr); for (let i = n; i > 0; i--) { let j = 0; while(j < arrSize) { if(arr[j] % i === 0) { j++; }else { break; } if(j === arrSize) { return i; } } } } console.log(generalizedGCD(4, [2, 6, 4, 8])); // Output => 2
Here was the answer I was looking for. The best way to find the gcd of n numbers is indeed using recursion.ie gcd(a,b,c)=gcd(gcd(a,b),c). But I was getting timeouts in certain programs when I did this. The optimization that was needed here was that the recursion should be solved using fast matrix multiplication algorithm.
Help with algorithm problem from SPOJ
I thought it would be a fun problem: Prime Path But...It is hard for me. My only idea is "To do something with knapsack problem".. and no other ideas. Could You track me for good way? It's not for any challenge or University homework. I just want to learn something. _ Ok, but firstly, how to find this prime numbers? Do i need to find all 4digit prime numbers, add it to graph? For now i have generating all prime numbers. http://pastebin.com/wbhRNRHQ Could You give me sample code to declare graph build on neighbour list?
Seems like a straightforward graph path finding problem. Take all 4 digit primes as the vertices. Connect two with an edge, if we can go from one to the other. Now given two, you need to find the shortest path between them, in the graph we just formed. A simple BFS (breadth-first-search) should do for that. For programming contests with time limits, you could even hardcode every possible prime pair path and get close to zero running time!
Build a graph where the nodes are all the 4 digit prime numbers, and there are arcs everywhere two numbers have three digits in common. From there, it's a basic graph traversal to find the lowest-cost path from one node to another.
I came across a similar question where I had to convert one 4 digit prime number 1033 to another 4 digit prime number 3739 in minimum number of steps. I was able to solve the problem, it might not be efficient but here is the working code for the same. Below code has been written in Java import java.util.*; public class PrimeNumberProblem { public static void main(String... args) { System.out.println("Minimum number of steps required for converting 1033 to 3739 are = " + getMinSteps(1033, 3739)); } public static int getMinSteps(int a, int b) { if (a == b) return 0; List<Integer> primes = new ArrayList<>(); // get all the 4 digit prime numbers primes = getPrimeNumbers(); // consists of graph with vertices as all the prime numbers Graph graph = addNumbersToGraph(primes); // adding edges to the graph vertices Graph finalGraph = addWeightToGraph(graph); // min number of steps required int result = findShortestRoute(finalGraph.getVertex(a), finalGraph.getVertex(b)); return result; } private static int findShortestRoute(Vertex source, Vertex dest) { if (source.getVertexValue() == dest.getVertexValue()) return 0; // step 1 Initialize the queue. Also Map to store path Queue<Vertex> visitedQueue = new LinkedList<>(); Map<Vertex, Vertex> currentPrevMap = new HashMap<Vertex, Vertex>(); // step 2 start from visiting S (starting node), and mark it visited, add to queue Map<Integer, Boolean> visited = new HashMap<Integer, Boolean>(); visited.put(source.getVertexValue(), true); visitedQueue.add(source); int level = 0; // step 3 Repeat until queue is empty while (!visitedQueue.isEmpty()) { // step 4 remove from queue Vertex current = visitedQueue.remove(); if (current.getVertexValue() == dest.getVertexValue()) { printPath(source, dest, currentPrevMap); return level; } else if (current.getAdjacentVertices().size() > 0) { level++; } // step 5 add each of the unvisited neighbour and mark visited for (Vertex adjacentVertex : current.getAdjacentVertices()) { Integer value = adjacentVertex.getVertexValue(); if (value == dest.getVertexValue()) { currentPrevMap.put(adjacentVertex, current); printPath(source, dest, currentPrevMap); return level; } if (visited.get(value) == null) { currentPrevMap.put(adjacentVertex, current); // mark visited and enqueue it visited.put(value, true); visitedQueue.add(adjacentVertex); } } } // not found System.out.println("Dest vertex not found"); return -1; } private static void printPath(Vertex source, Vertex dest, Map<Vertex, Vertex> currentPrevMap) { Vertex node = dest; System.out.println("Reverse Path from source: " + source.getVertexValue() + " to dest: " + dest.getVertexValue()); while (node != source) { System.out.println(node.getVertexValue()); node = currentPrevMap.get(node); } System.out.println(source.getVertexValue()); } private static Graph addWeightToGraph(Graph graph) { List<Vertex> vertices = graph.getAllVertices(); for (Vertex i : vertices) { for (Vertex j : vertices) { if (i.equals(j)) continue; if (distance(i, j) == 1) { i.getAdjacentVertices().add(j); // i.addEdge(new Edge(i, j, 1)); } } } return graph; } private static int distance(Vertex source, Vertex dest) { if (source.getVertexValue() == dest.getVertexValue()) { return 0; } char[] numA = extractIntegers(source.getVertexValue()); char[] numB = extractIntegers(dest.getVertexValue()); int len1 = numA.length; int tracker = 0; for (int i = 0; i < len1; i++) { if (numA[i] != numB[i]) { numA[i] = numB[i]; tracker++; String sA = String.copyValueOf(numA); String sB = String.copyValueOf(numB); // if we have reached destination if (Integer.parseInt(sA) == Integer.parseInt(sB)) { return tracker; } } } return tracker; } private static char[] extractIntegers(int i) { char[] arr = Integer.toString(i).toCharArray(); return arr; } private static Graph addNumbersToGraph(List<Integer> primes) { Graph g = new Graph(); for (Integer prime : primes) { g.addVertex(new Vertex(prime)); } return g; } private static List<Integer> getPrimeNumbers() { List<Integer> fourDigitPrimes = new ArrayList<>(); fourDigitPrimes.add(1033); fourDigitPrimes.add(1733); fourDigitPrimes.add(3733); fourDigitPrimes.add(3739); // for (int i = 1000; i < 9999; i++) { // if (isPrime(i)) // fourDigitPrimes.add(i); // } return fourDigitPrimes; } private static boolean isPrime(int i) { for (int k = 2; k < Math.sqrt(i); k++) { if (i % k == 0) return false; } return true; } } class Graph { public List<Vertex> vertexList = new ArrayList<Vertex>(); public void addVertex(Vertex V) { vertexList.add(V); } public List getAllAdjacentNodes(Vertex V) { return V.getAdjacentVertices(); } public List getAllVertices() { return vertexList; } public Vertex getVertex(int val) { Iterator<Vertex> keys = vertexList.iterator(); while (keys.hasNext()) { Vertex v = keys.next(); if (v.getVertexValue() == val) return v; } return null; } } class Vertex { int value; private List<Vertex> adjacentVertices = new ArrayList<Vertex>(); public Vertex(int v) { this.value = v; } public List<Vertex> getAdjacentVertices() { return adjacentVertices; } public int getVertexValue() { return value; } #Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Vertex vertex = (Vertex) o; return value == vertex.value; } #Override public int hashCode() { return value; } }
Look into "breadth-first search". Also worth bearing in mind here that the problem can be approached "from both ends" simultaneously (a chain from numbers X to Y can be reversed to get Y to X, and you can exploit this). Precalculating primes will avoid much computation along the way.
I'd run a BFS using probable prime testing, which would work relatively well with only 4 digit numbers. With only 4 digits, also, you may want to use more exacting methods to produce all primes to compare against for faster prime checking.
Could You give me sample code to declare graph build on neighbour list? here is a sample code for breadth first search public static final int MAX = 10000; boolean[] prime = new boolean[MAX]; int[] dist = new int[MAX]; //get digit i [1 to 4] in num public int getDigit(int num,int i){ return num % ((int)Math.pow(10, i)) / ((int) Math.pow(10, i-1)); } //set digit i to d public int setDigit(int num,int i,int d){ return (num - getDigit(num, i)*(int)Math.pow(10, i-1)) + d * (int)Math.pow(10,i-1); } public int bfs(int start,int end){ Queue<Integer> q = new LinkedList<Integer>(); q.add(start); HashSet<Integer> visited = new HashSet<Integer>(); visited.add(start); dist[start] = 0; int x,y,d = 0; while (q.size() > 0){ x = q.poll(); d = dist[x]; if (x == end) return d; for (int i = 1; i < 5; i++) { //digit number i for (int j = 0; j < 10; j++) { //avoid setting last digit if (j == 0 && i == 4) continue; //set digit number i to j y = setDigit(x, i, j); if (prime[y] && y != x && !visited.contains(y)){ q.add(y); visited.add(y); dist[y] = d + 1; } } } } return -1; }
Here is my solution using BFS and I have already saved all 4 digit prime numbers into an array as there is no need to write a function to calculate the prime numbers. I hope it helps #include<stdio.h> int hash[10000]; int a,b,ans,level,new_num,count; int prime[] = {1009,1013,1019,1021,1031,1033,1039,1049,1051,1061,1063,1069,1087,1091,1093,1097,1103,1109,1117,1123,1129,1151,1153,1163,1171,1181,1187,1193,1201,1213,1217,1223,1229,1231,1237,1249,1259,1277,1279,1283,1289,1291,1297,1301,1303,1307,1319,1321,1327,1361,1367,1373,1381,1399,1409,1423,1427,1429,1433,1439,1447,1451,1453,1459,1471,1481,1483,1487,1489,1493,1499,1511,1523,1531,1543,1549,1553,1559,1567,1571,1579,1583,1597,1601,1607,1609,1613,1619,1621,1627,1637,1657,1663,1667,1669,1693,1697,1699,1709,1721,1723,1733,1741,1747,1753,1759,1777,1783,1787,1789,1801,1811,1823,1831,1847,1861,1867,1871,1873,1877,1879,1889,1901,1907,1913,1931,1933,1949,1951,1973,1979,1987,1993,1997,1999,2003,2011,2017,2027,2029,2039,2053,2063,2069,2081,2083,2087,2089,2099,2111,2113,2129,2131,2137,2141,2143,2153,2161,2179,2203,2207,2213,2221,2237,2239,2243,2251,2267,2269,2273,2281,2287,2293,2297,2309,2311,2333,2339,2341,2347,2351,2357,2371,2377,2381,2383,2389,2393,2399,2411,2417,2423,2437,2441,2447,2459,2467,2473,2477,2503,2521,2531,2539,2543,2549,2551,2557,2579,2591,2593,2609,2617,2621,2633,2647,2657,2659,2663,2671,2677,2683,2687,2689,2693,2699,2707,2711,2713,2719,2729,2731,2741,2749,2753,2767,2777,2789,2791,2797,2801,2803,2819,2833,2837,2843,2851,2857,2861,2879,2887,2897,2903,2909,2917,2927,2939,2953,2957,2963,2969,2971,2999,3001,3011,3019,3023,3037,3041,3049,3061,3067,3079,3083,3089,3109,3119,3121,3137,3163,3167,3169,3181,3187,3191,3203,3209,3217,3221,3229,3251,3253,3257,3259,3271,3299,3301,3307,3313,3319,3323,3329,3331,3343,3347,3359,3361,3371,3373,3389,3391,3407,3413,3433,3449,3457,3461,3463,3467,3469,3491,3499,3511,3517,3527,3529,3533,3539,3541,3547,3557,3559,3571,3581,3583,3593,3607,3613,3617,3623,3631,3637,3643,3659,3671,3673,3677,3691,3697,3701,3709,3719,3727,3733,3739,3761,3767,3769,3779,3793,3797,3803,3821,3823,3833,3847,3851,3853,3863,3877,3881,3889,3907,3911,3917,3919,3923,3929,3931,3943,3947,3967,3989,4001,4003,4007,4013,4019,4021,4027,4049,4051,4057,4073,4079,4091,4093,4099,4111,4127,4129,4133,4139,4153,4157,4159,4177,4201,4211,4217,4219,4229,4231,4241,4243,4253,4259,4261,4271,4273,4283,4289,4297,4327,4337,4339,4349,4357,4363,4373,4391,4397,4409,4421,4423,4441,4447,4451,4457,4463,4481,4483,4493,4507,4513,4517,4519,4523,4547,4549,4561,4567,4583,4591,4597,4603,4621,4637,4639,4643,4649,4651,4657,4663,4673,4679,4691,4703,4721,4723,4729,4733,4751,4759,4783,4787,4789,4793,4799,4801,4813,4817,4831,4861,4871,4877,4889,4903,4909,4919,4931,4933,4937,4943,4951,4957,4967,4969,4973,4987,4993,4999,5003,5009,5011,5021,5023,5039,5051,5059,5077,5081,5087,5099,5101,5107,5113,5119,5147,5153,5167,5171,5179,5189,5197,5209,5227,5231,5233,5237,5261,5273,5279,5281,5297,5303,5309,5323,5333,5347,5351,5381,5387,5393,5399,5407,5413,5417,5419,5431,5437,5441,5443,5449,5471,5477,5479,5483,5501,5503,5507,5519,5521,5527,5531,5557,5563,5569,5573,5581,5591,5623,5639,5641,5647,5651,5653,5657,5659,5669,5683,5689,5693,5701,5711,5717,5737,5741,5743,5749,5779,5783,5791,5801,5807,5813,5821,5827,5839,5843,5849,5851,5857,5861,5867,5869,5879,5881,5897,5903,5923,5927,5939,5953,5981,5987,6007,6011,6029,6037,6043,6047,6053,6067,6073,6079,6089,6091,6101,6113,6121,6131,6133,6143,6151,6163,6173,6197,6199,6203,6211,6217,6221,6229,6247,6257,6263,6269,6271,6277,6287,6299,6301,6311,6317,6323,6329,6337,6343,6353,6359,6361,6367,6373,6379,6389,6397,6421,6427,6449,6451,6469,6473,6481,6491,6521,6529,6547,6551,6553,6563,6569,6571,6577,6581,6599,6607,6619,6637,6653,6659,6661,6673,6679,6689,6691,6701,6703,6709,6719,6733,6737,6761,6763,6779,6781,6791,6793,6803,6823,6827,6829,6833,6841,6857,6863,6869,6871,6883,6899,6907,6911,6917,6947,6949,6959,6961,6967,6971,6977,6983,6991,6997,7001,7013,7019,7027,7039,7043,7057,7069,7079,7103,7109,7121,7127,7129,7151,7159,7177,7187,7193,7207,7211,7213,7219,7229,7237,7243,7247,7253,7283,7297,7307,7309,7321,7331,7333,7349,7351,7369,7393,7411,7417,7433,7451,7457,7459,7477,7481,7487,7489,7499,7507,7517,7523,7529,7537,7541,7547,7549,7559,7561,7573,7577,7583,7589,7591,7603,7607,7621,7639,7643,7649,7669,7673,7681,7687,7691,7699,7703,7717,7723,7727,7741,7753,7757,7759,7789,7793,7817,7823,7829,7841,7853,7867,7873,7877,7879,7883,7901,7907,7919,7927,7933,7937,7949,7951,7963,7993,8009,8011,8017,8039,8053,8059,8069,8081,8087,8089,8093,8101,8111,8117,8123,8147,8161,8167,8171,8179,8191,8209,8219,8221,8231,8233,8237,8243,8263,8269,8273,8287,8291,8293,8297,8311,8317,8329,8353,8363,8369,8377,8387,8389,8419,8423,8429,8431,8443,8447,8461,8467,8501,8513,8521,8527,8537,8539,8543,8563,8573,8581,8597,8599,8609,8623,8627,8629,8641,8647,8663,8669,8677,8681,8689,8693,8699,8707,8713,8719,8731,8737,8741,8747,8753,8761,8779,8783,8803,8807,8819,8821,8831,8837,8839,8849,8861,8863,8867,8887,8893,8923,8929,8933,8941,8951,8963,8969,8971,8999,9001,9007,9011,9013,9029,9041,9043,9049,9059,9067,9091,9103,9109,9127,9133,9137,9151,9157,9161,9173,9181,9187,9199,9203,9209,9221,9227,9239,9241,9257,9277,9281,9283,9293,9311,9319,9323,9337,9341,9343,9349,9371,9377,9391,9397,9403,9413,9419,9421,9431,9433,9437,9439,9461,9463,9467,9473,9479,9491,9497,9511,9521,9533,9539,9547,9551,9587,9601,9613,9619,9623,9629,9631,9643,9649,9661,9677,9679,9689,9697,9719,9721,9733,9739,9743,9749,9767,9769,9781,9787,9791,9803,9811,9817,9829,9833,9839,9851,9857,9859,9871,9883,9887,9901,9907,9923,9929,9931,9941,9949,9967,9973}; int size = sizeof(prime)/sizeof(prime[0]); int bfs(int,int); typedef struct q{ int x, c; } queue; queue qq[10000]; int isprime(int x) { int l,r,m; l=m=0; r=size-1; while (l <= r) { int m = l + (r-l)/2; if (prime[m] == x) return 1; if (prime[m] < x) l = m + 1; else r = m - 1; } return 0; } int bfs(int num1,int num2) { int i,j,k,p,q,n; new_num=p=q=0; i=0; j=1; qq[i].x = num1; qq[i].c = 0; hash[num1] = 1; while(i!=j) { n = qq[i].x; level = qq[i].c; if(n==num2) { count = level; return count; } level++; p = n%1000; for(k=1;k<10;k++) { new_num = (k*1000)+ p; if(isprime(new_num)&&(new_num!=n)&&(!hash[new_num])) { hash[new_num] = 1; qq[j].x = new_num; qq[j].c = level; j++; }} p=q=new_num=0; p = n/1000; q = n%100; for(k=0;k<10;k++) { new_num = (p*1000)+k*100+q; if(isprime(new_num)&&(new_num!=n)&&(!hash[new_num])) { hash[new_num] = 1; qq[j].x = new_num; qq[j].c = level; j++; }} p=q=new_num=0; p = n/100; q = n%10; for(k=0;k<10;k++) { new_num = (p*100)+k*10+q; if(isprime(new_num)&&(new_num!=n)&&(!hash[new_num])) { hash[new_num] = 1; qq[j].x = new_num; qq[j].c = level; j++; }} p=q=new_num=0; p = n/10; for(k=0;k<10;k++) { new_num = (p*10)+k; if(isprime(new_num)&&(new_num!=n)&&(!hash[new_num])) { hash[new_num] = 1; qq[j].x = new_num; qq[j].c = level; j++; }} p=q=new_num=0; i++; } return -1;} int main() { int v,tc; setbuf(stdout,NULL); scanf("%d",&tc); for(v=1;v<=tc;v++) { int i,j; a=b=ans=level=new_num=count=0; for(i=0;i<10000;i++) {qq[i].x=0; qq[i].c=0; hash[i]=0;} scanf("%d%d",&a,&b); if(a==b) { ans = 0;} else { ans = bfs(a,b);} printf("Case #%d\n", v); if(ans==-1) { printf("Impossible\n"); } else {printf("%d\n",ans);} } return 0; }
My Python solution using BFS: import queue # Class to represent a graph class Graph: def __init__(self, V): self.V = V # No. of vertices self.prime_list = [[] for i in range(V)] # function to add an edge to graph def addedge(self, V1, V2): self.prime_list[V1].append(V2) self.prime_list[V2].append(V1) def bfs(self, in1, in2): visited = [0] * self.V que = queue.Queue() visited[in1] = 1 que.put(in1) while not que.empty(): prime_index = que.get() i = 0 while i < len(self.prime_list[prime_index]): if not visited[self.prime_list[prime_index][i]]: visited[self.prime_list[prime_index][i]] = visited[prime_index] + 1 que.put(self.prime_list[prime_index][i]) if self.prime_list[prime_index][i] == in2: return visited[self.prime_list[prime_index][i]] - 1 i += 1 # // Finding all 4 digit prime numbers def SieveOfEratosthenes(v): # Create a boolean array "prime[0..n]" and initialize all entries it as true. A value in prime[i] will be # finally be false if i is Not a prime, else true. n = 9999 prime = [True] * (n + 1) p = 2 while p * p <= 9999: if prime[p]: i = p * p while i <= 9999: prime[i] = False i = i + p p = p + 1 # v = [] for i in range(1000, n + 1): if prime[i]: v.append(i) return v def compare(a, b): diff = 0 while a: if a % 10 != b % 10: diff += 1 a //= 10 b //= 10 # If the numbers differ only by a single # digit return true else false if diff > 1: return False return True def shortestPath(num1, num2): # Generate all 4 digit pset = [] SieveOfEratosthenes(pset) # Create a graph where node numbers # are indexes in pset[] and there is # an edge between two nodes only if # they differ by single digit. g = Graph(len(pset)) for i in range(len(pset)): for j in range(i + 1, len(pset)): if compare(pset[i], pset[j]): g.addedge(i, j) # Since graph nodes represent indexes # of numbers in pset[], we find indexes of num1 and num2. in1, in2 = None, None for j in range(len(pset)): if pset[j] == num1: in1 = j for j in range(len(pset)): if pset[j] == num2: in2 = j return g.bfs(in1, in2) # Driver code if __name__ == '__main__': num1 = 1033 num2 = 8179 print(shortestPath(num1, num2))