2d vector c++ use in Longest Common Substring - c++

I am working on codechef practice problem in which I have to find longest common substring. ( Its practice problem so don't down vote )
Following wiki and some resources online I got the algorithm
https://en.wikipedia.org/wiki/Longest_common_substring_problem
After understanding I wrote the algorithm in c++ , but its compiling but not running successfully . Throwing error while assigning value to vector matrix .
An invalid parameter was passed to a function that considers invalid parameters fatal.
1) Whats wrong with my LCSubstring function
#include<iostream>
#include<string>
#include<vector>
using namespace std;
int max(int a, int b) {
return a > b ? a : b;
}
int LCSubString(string str1 , string str2) {
// create 2d matrix
vector<vector<int>> matrix;
int maxlength = 0;
for (int i = 0; i <= str1.length(); i++) {
for (int j = 0; j <= str2.length(); j++) {
if (i == 0 && j == 0) {
matrix[i][j] = 0;
continue;
}
if (str1[i - 1] == str2[j - 1]) {
matrix[i][j] = matrix[i - 1][j - 1] + 1;
maxlength = max(maxlength, matrix[i][j]);
}
else {
matrix[i][j] = 0;
}
}
}
return maxlength;
}
int main()
{
int t;
int count = 0;
string str;
int len;
cin >> t;
while (t--) {
cin>> str;
len = LCSubString(str, "chef");
if (len >= 2) {
count++;
}
}
cout << count << endl;
return 0;
}

You did not properly initialize std::vector<std::vector<int>> matrix. They do not automatically resize when you access them with [], you need to set the proper size beforehand, like this:
vector<vector<int>> matrix(str.length()+1);
for (int i = 0; i <= str1.length(); ++i)
matrix[i] = vector<int>(str2.length()+1, 0);
Additionally, you are not properly checking for i == 0 or j == 0. If only one of them is zero then the first if in your loop won't hit and you subsequently try to read string[-1]. I don't know whether it would be correct for your algorithm, but try using logical or (||) instead of and (&&).

Related

Why some compiler shows unfavorable output for a specific input?

Look at this code, In my VS code or some online compilers it gives favorable output, but when I'm submitting this on HackerRank or this online compiler I'm getting wrong output but only when I provide input as: 1 1 1 100...and I'm not able to spot the Error?..I'm providing question for reference.
/*There will be two arrays of integers. Determine all integers that satisfy
the following two conditions:
The elements of the first array are all factors of the integer being
considered
The integer being considered is a factor of all elements of the second array
These numbers are referred to as being between the two arrays. Determine how
many such numbers exist.
*/
#include <iostream>
int main()
{
int count1, count2;
int num1[20], num2[20];
std::cin >> count1 >> count2;
for (int i = 0; i < count1; i++)
{
std::cin >> num1[i];
}
for (int i = 0; i < count2; i++)
{
std::cin >> num2[i];
}
int occurence_firstarray = 0, occurence_secondarray = 0, totalvalid_occurence = 0;
for (int i = num1[count1 - 1]; i < num2[1]; i++)
{
occurence_firstarray = 0;
occurence_secondarray = 0;
for (int j = 0; j < count1; j++)
{
if (i % num1[j] == 0)
{
occurence_firstarray++;
}
}
if (occurence_firstarray == count1)
{
for (int p = 0; p < count2; p++)
{
if (num2[p] % i == 0)
{
occurence_secondarray++;
}
}
}
if (occurence_secondarray == count2)
{
totalvalid_occurence++;
}
}
std::cout << totalvalid_occurence;
return (0);
}
Considering your inputs: 1 1 1 100,
What are you doing in this code is You are pointing on index beyond your second array's size limit i < num2[1], this is why you are getting wrong outputs.
Do some changes as, i <= num2[0];

Issue with C++ Srand Values

So I'm creating a lottery ticket with random values and then sorting it. I'm not worried about the sorting technique since the teacher isn't looking for classes etc. on this assignment and it works, however, my ticket values that I produce - despite using srand (time(0)) and then later the rand() % 40 + 1 - which I think should make my randoms between 1-40... but mainTicket[0] always equals 0. Any ideas? Sorry about the formatting, made me add extra spaces and mess up my indention.
#include <iostream>
#include <cstdlib>
#include <time.h>
using namespace std;
void mainLotto (int main[]);
void lottoSort (int ticketArr[]);
int main()
{
int mainTicket[5];
srand (time(0));
mainLotto(mainTicket);
do
{
lottoSort(mainTicket);
} while (mainTicket[0] > mainTicket[1] || mainTicket[1] > mainTicket[2] || mainTicket[2] > mainTicket[3] || mainTicket[3] > mainTicket[4] || mainTicket[4] > mainTicket[5]);
for (int i = 0; i < 5; i++)
{
cout << mainTicket[i] << "\n\n";
}
return 0;
}
///
/// <> Creates the actual lottery ticket
///
void mainLotto (int main[])
{
// Creating the ticket
for (int i = 0; i < 5; i++)
{
main[i] = rand() % 40 + 1;
}
}
///
/// <> Sorts the actual lottery ticket
///
void lottoSort (int ticketArr[])
{
// Sorting the ticket
for (int j = 0; j < 5; j++)
{
if (ticketArr[j] > ticketArr[j+1])
{
int temp;
temp = ticketArr[j+1];
ticketArr[j+1] = ticketArr[j];
ticketArr[j] = temp;
}
}
}
I see two problems with your arrays being accessed out of bounds:
Here:
int main()
{
int mainTicket[5];
srand(time(0));
mainLotto(mainTicket);
do
{
lottoSort(mainTicket);
}
while(mainTicket[0] > mainTicket[1] || mainTicket[1] > mainTicket[2]
|| mainTicket[2] > mainTicket[3] || mainTicket[3] > mainTicket[4]);
// || mainTicket[4] > mainTicket[5]); // OUT OF BOUNDS!!!
for(int i = 0; i < 5; i++)
{
cout << mainTicket[i] << "\n\n";
}
return 0;
}
And here:
void lottoSort(int ticketArr[])
{
// Sorting the ticket
for(int j = 0; j < 4; j++) // j < 4 NOT 5!!! <== WAS OUT OF BOUNDS
{
if(ticketArr[j] > ticketArr[j + 1])
{
int temp;
temp = ticketArr[j + 1];
ticketArr[j + 1] = ticketArr[j];
ticketArr[j] = temp;
}
}
}
Likely the sort routine was dragging in a zero from out side the array bounds.
I just printed the item you claim to be always zero, after the mainLotto() and it yielded 30.
I suspect the problem lies where you tell us not to look. :)
In the sorting function you do:
for (int j = 0; j < 5; j++) {
if (ticketArr[j] > ticketArr[j + 1]) {
The array is of size 5. Your j will take eventually a value equal to 4.
Then you do ticketArr[j + 1], which is actually an out of bound access.
The fix is to go until 4 in your loop, not 5.
As Galik said, mainTicket[4] > mainTicket[5] is also an out of bounds access and after reading my answer, you should be able to understand why. :)

Duplicate numbers in an array [duplicate]

This question already has answers here:
Deleting duplicates in the array
(2 answers)
Closed 8 years ago.
I need to write a program where I have to print the numbers which occur twice or more than twice in the array. To make things simpler, I am working on a sorted array.
Here is my code.
#include <stdio.h>
int main()
{
int n,i;
int a[10]={2,2,2,4,6,6,9,10,10,11};
printf("%d\n",a[10]);
for(i=0;i<10;++i)
{
if(a[i]==a[i+1] && a[i]!=a[i-1])
printf("%d ",a[i]);
else
continue;
}
return 0;
}
The code seems to work fine but I do not like my code because at some point, the loop compares the value of a[0] with a[-1] and a[9] with a[10] and both of these, a[-1] and a[10], are garbage values. I am sure there are better ways to do it but I am unable to think of any.
Also, I need to extend the above program to count the frequency of duplicate numbers.
Help is appreciated. Thanks!
First, you can't access a[10] in your printf line, this is outside your array.
This should work fine.
#include <stdio.h>
int main()
{
int n,i;
int a[10]={2,2,2,4,6,6,9,10,10,11};
for(i=0; i < 9; ++i)
{
if(a[i] == a[i+1])
if(i > 0 && a[i] == a[i-1])
continue;
else
printf("%d ",a[i]);
}
return 0;
}
Edit: Or you can use the shorter yet harder to read:
for(i=0; i < 9; ++i)
{
if(a[i] == a[i+1] && (!i || a[i] != a[i-1]))
printf("%d ",a[i]);
}
See code below for the solution, which will print only the duplicate numbers from the array and how many times they occur.
I added the int c which is used for your count. It is initially set to 1, and increased by 1 for each duplicate number.
#include <stdio.h>
using namespace std;
int main() {
int n,i,c;
int a[10]={2,2,2,4,6,6,9,10,10,11};
c = 1;
for(i=0; i < 9; ++i)
{
if (a[i] == a[i+1]) {
n = a[i];
c += 1;
} else {
if (c > 1) {
printf("Number: %d, Occurences: %d \n",n,c);
c = 1;
}
}
}
return 0;
}
Since the array is already sorted, it'd be easier to do something like this, with another loop inside the for loop.
int duplicateCount = 1; // Must be at least one instance of a value in the array
for(int i = 0; i < 9; ++i) {
int j = i;
while(j != 9 && a[j] == a[j + 1]) {
++j;
++duplicateCount;
}
i = j; // j is now at end of list of duplicates, so put i at the end as well,
// to be incremented to the next unique value at end of for loop iteration
printf("%d: %d\n", a[j], duplicateCount);
duplicateCount = 1; // Reset for next values
}
If you want to count the frequency of all the numbers, you can easily turn duplicateCount into an array of values to count the frequency of each unique value. For a better solution, you could use another data structure, such as a map.
You are really going to need to have two indexes that walk through your array.
Here's a start:
int i = 0;
int j;
while (i < 10) {
for (j = i+1; j < 10; ++j) if (a[i] != a[j]) break;
if (j !+ i+i) printf("%d\n", a[i]);
i = j;
}
You could use a functor, overload operator() and return a set (unique values). Assuming your array is sorted it's just a matter of comparing the previous one with the next and inserting it in the set if they equal. If they are not sorted then you have to go through the whole array for every entry. Below are two examples with output as an explanation.
#include <set>
using namespace std;
Unsorted array:
struct UnsortedArrayDuplicateEntries {
set<int> operator()(int* array, int size) {
set<int> duplicates;
for (int i = 0; i < size - 1; i++)
for (int j = i + 1;j < size; j++)
if (array[i] == array[j])
duplicates.insert(array[j]);
return duplicates;
}
};
Sorted array:
struct SortedArrayDuplicateEntries {
set<int> operator()(int* array, int size) {
set<int> duplicates;
for (int i = 0; i < size - 1; i++)
if (array[i] == array[i+1])
duplicates.insert(array[j]);
return duplicates;
}
};
Test sorted:
SortedArrayDuplicateEntries d;
int sorted[10]={2,2,2,4,6,6,9,10,10,11};
set<int> resultSorted = d(sorted,10);
for (int i : resultSorted) cout << i << endl;
Output sorted:
2
6
10
Test unsorted:
UnsortedArrayDuplicateEntries d;
int unsorted[10]={2,6,4,2,10,2,9,6,10,11};
set<int> resultUnsorted = d(unsorted,10);
for (int i : resultUnsorted) cout << i << endl;
Output unsorted:
2
6
10
I hope it helps!
#include <stdio.h>
int main(){
int i, a[10]={2,2,2,4,6,6,9,10,10,11};
int size = 10;
for(i=0;i<size;++i){
int tmp = a[i];
int c = 1;
while(++i < size && tmp == a[i])
++c;
if(c > 1)
printf("%d times %d\n", tmp, c);
--i;
}
return 0;
}

How to apply longest common subsequence algorithm on large strings?

How to apply longest common subsequence on bigger strings (600000 characters). Is there any way to do it in DP? I have done this for shorter strings.
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
using namespace std;
int dp[1005][1005];
char a[1005], b[1005];
int lcs(int x,int y)
{
if(x==strlen(a)||y==strlen(b))
return 0;
if(dp[x][y]!=-1)
return dp[x][y];
else if(a[x]==b[y])
dp[x][y]=1+lcs(x+1,y+1);
else
dp[x][y]=max(lcs(x+1,y),lcs(x,y+1));
return dp[x][y];
}
int main()
{
while(gets(a)&&gets(b))
{
memset(dp,-1,sizeof(dp));
int ret=lcs(0,0);
printf("%d\n",ret);
}
}
You should take a look at this article which discusses the various design and implementation considerations. It is pointed out that you can look at Hirschberg's algorithm that finds optimal alignments between two strings using Edit distance (or Levenshtein distance). It can simplify the amount of space required on your behalf.
At the bottom you will find the "space-efficient LCS" defined thusly as a kind of mixed/pseudocode where m is the length of A and n is the length of B:
int lcs_length(char *A, char *B) {
// Allocate storage for one-dimensional arrays X and Y.
for (int i = m; i >= 0; i--) {
for (int j = n; j >= 0; j--) {
if (A[i] == '\0' || B[j] == '\0') {
X[j] = 0;
}
else if (A[i] == B[j]) {
X[j] = 1 + Y[j+1];
}
else {
X[j] = max(Y[j], X[j+1]);
}
}
// Copy contents of X into Y. Note that the "=" operator here
// might not do what you expect. If Y and X are pointers then
// it will assign the address and not copy the contents, so in
// that case you'd do a memcpy. But they could be a custom
// data type with an overridden "=" operator.
Y = X;
}
return X[0];
}
If you are interested here is a paper about LCS on strings from large alphabets. Find algorithm Approx2LCS in section 3.2.
First, use bottom-up approach of dynamic programming:
// #includes and using namespace std;
const int SIZE = 1000;
int dp[SIZE + 1][SIZE + 1];
char a[SIZE + 1], b[SIZE + 1];
int lcs_bottomUp(){
int strlenA = strlen(a), strlenB = strlen(b);
for(int y = 0; y <= strlenB; y++)
dp[strlenA][y] = 0;
for(int x = strlenA - 1; x >= 0; x--){
dp[x][strlenB] = 0;
for(int y = strlenB - 1; y >= 0; y--)
dp[x][y] = (a[x]==b[y]) ? 1 + dp[x+1][y+1] :
max(dp[x+1][y], dp[x][y+1]);
}
return dp[0][0];
}
int main(){
while(gets(a) && gets(b)){
printf("%d\n", lcs_bottomUp());
}
}
Observe that you only need to keep 2 rows (or columns), one for dp[x] and another for dp[x + 1]:
// #includes and using namespace std;
const int SIZE = 1000;
int dp_x[SIZE + 1]; // dp[x]
int dp_xp1[SIZE + 1]; // dp[x + 1]
char a[SIZE + 1], b[SIZE + 1];
int lcs_bottomUp_2row(){
int strlenA = strlen(a), strlenB = strlen(b);
for(int y = 0; y <= strlenB; y++)
dp_x[y] = 0; // assume x == strlenA
for(int x = strlenA - 1; x >= 0; x--){
// x has been decreased
memcpy(dp_xp1, dp_x, sizeof(dp_x)); // dp[x + 1] <- dp[x]
dp_x[strlenB] = 0;
for(int y = strlenB - 1; y >= 0 ; y--)
dp_x[y] = (a[x]==b[y]) ? 1 + dp_xp1[y+1] :
max(dp_xp1[y], dp_x[y+1]);
}
return dp_x[0]; // assume x == 0
}
int main(){
while(gets(a) && gets(b)){
printf("%d\n", lcs_bottomUp_2row());
}
}
Now it's safe to change SIZE to 600000.
As OP stated, the other answers are taking too much time, mainly due to the fact that for each outter iteration, 600000 characters are being copied.
To improve it, one could, instead of physically changing column, change it logically. Thus:
int spaceEfficientLCS(std::string a, std::string b){
int i, j, n = a.size(), m = b.size();
// Size of columns is based on the size of the biggest string
int maxLength = (n < m) ? m : n;
int costs1[maxLength+1], costs2[maxLength+1];
// Fill in data for costs columns
for (i = 0; i <= maxLength; i++){
costs1[i] = 0;
costs2[i] = 0;
}
// Choose columns in a way that the return value will be costs1[0]
int* mainCol, *secCol;
if (n%2){
mainCol = costs2;
secCol = costs1;
}
else{
mainCol = costs1;
secCol = costs2;
}
// Compute costs
for (i = n; i >= 0; i--){
for (j = m; j >= 0; j--){
if (a[i] == '\0' || b[j] == '\0') mainCol[j] = 0;
else mainCol[j] = (a[i] == b[j]) ? secCol[j+1] + 1 :
std::max(secCol[j], mainCol[j+1]);
}
// Switch logic column
int* aux = mainCol;
mainCol = secCol;
secCol = aux;
}
return costs1[0];
}

C/C++ How can I get unique value from 2 arrays?

I need to get the unique value from 2 int arrays
Duplicate is allowed
There is just one unique value
like :
int arr1[3]={1,2,3};
int arr2[3]={2,2,3};
and the value i want to get is :
int unique[]={1}
how can i do this?
im already confused in my 'for' and 'if'
this was not homework
i know how to merge 2 arrays and del duplicate values
but i alse need to know which array have the unique value
plz help me :)
and here is some code i did
int arr1[3]={1,2,3}
int arr2[3]={2,2,3}
int arrunique[1];
bool unique = true;
for (int i=0;i!=3;i++)
{
for (int j=0;j!=3;j++)
{
if(arr1[i]==arr2[j])
{
unique=false;
continue;
}
else
{
unique=true;
}
if(unique)
{
arrunique[0]=arr1[i]
break;
}
}
cout << arrunique[0];
Assuming:
You have two arrays of different length,
The arrays are sorted
The arrays can have duplicate values in them
You want to get the list of values that only appear in one of the arrays
including their duplicates if present
You can do (untested):
// Assuming arr1[], arr2[], and lengths as arr1_length
int i = 0,j = 0, k = 0;
int unique[arr1_length + arr2_length];
while(i < arr1_length && j < arr2_length) {
if(arr1[i] == arr2[j]) {
// skip all occurrences of this number in both lists
int temp = arr1[i];
while(i < arr1_length && arr1[i] == temp) i++;
while(j < arr2_length && arr2[j] == temp) j++;
} else if(arr1[i] > arr2[j]) {
// the lower number only occurs in arr2
unique[k++] = arr2[j++];
} else if(arr2[j] > arr1[i]) {
// the lower number only occurs in arr1
unique[k++] = arr1[i++];
}
}
while(i < arr1_length) {
// if there are numbers still to read in arr1, they're all unique
unique[k++] = arr1[i++];
}
while(j < arr2_length) {
// if there are numbers still to read in arr2, they're all unique
unique[k++] = arr2[j++];
}
Some alternatives:
If you don't want the duplicates in the unique array, then you can skip all occurrences of this number in the relevant list when you assign to the unique array.
If you want to record the position instead of the values, then maintain two arrays of "unique positions" (one for each input array) and assign the value of i or j to the corresponding array as appropriate.
If there's only one unique value, change the assignments into the unique array to return.
Depending on your needs, you might also want to look at set_symmetric_difference() function of the standard library. However, its treatment of duplicate values makes its use a bit tricky, to say the least.
#include <stdio.h>
#include <stdlib.h>
int cmp ( const void *a , const void *b )
{
return *(int *)a - *(int *)b;
}
int main()
{
int arr1[5] = {5,4,6,3,1};
int arr2[3] = {5, 8, 9};
int unique[8];
qsort(arr1,5,sizeof(arr1[0]),cmp);
printf("\n");
qsort(arr2,3,sizeof(arr2[0]),cmp);
//printf("%d", arr1[0]);
int i = 0;
int k = 0;
int j = -1;
while (i < 5 && k < 3)
{
if(arr1[i] < arr2[k])
{
unique[++j] = arr1[i];
i++;
}
else if (arr1[i] > arr2[k])
{
unique[++j] = arr2[k];
k++;
}
else
{
i++;
k++;
}
}
//int len = j;
int t = 0;
if(i == 5)
{
for(t = k; t < 3; t++)
unique[++j] = arr2[t];
}
else
for(t = i; t < 5; t++)
unique[++j] = arr2[t];
for(i = 0; i <= j; i++)
printf("%d ", unique[i]);
return 0;
}
This is my codes,though there is a good answer .
I didn't realize the idea that know which array have the unique value.
I also think that the right answer that you chose didn't , either.
Here is my version of the algorithm for finding identical elements in sorted arrays on Python in C ++, it works in a similar way
def unique_array(array0 : (int), array1 : (int)) -> (int):
index0, index1, buffer = 0, 0, []
while index0 != len(array0) and index1 != len(array1):
if array0[index0] < array1[index1]:
buffer.append(array0[index0])
index0 += 1
elif array0[index0] > array1[index1]:
buffer.append(array1[index1])
index1 += 1
else:
index0 += 1; index1 += 1
buffer.extend(array0[index0 : len(array0)])
buffer.extend(array1[index1 : len(array1)])
return buffer