two strings of integers. Check if the second one is substring - c

#include <stdio.h>
int main() {
int x[100], y[100], i, j, dim1, dim2, subsir=0;
scanf("%d", &dim1);
for(i=0; i<dim1; i++)
{
scanf("%d", &x[i]);
}
scanf("%d", &dim2);
for(j=0; j<dim2; j++)
{
scanf("%d", &y[j]);
}
if(dim1<dim2)
{
printf("no");
return 0;
}
for(i=0; i<dim1; i++)
for(j=0; j<dim2; j++)
{
if(x[i]==y[j])
subsir=1;
}
if(subsir==1)
{
printf("yes");
}
else
{
printf("no");
}
return 0;
}
Consider two strings of integers. Check if the second string is a substring of the first in C.(the substring consists of consecutive elements of the first string)

You can achieve your goal with a brute force approach, trying every position from 0 to dim1 - dim2.
Here is a modified version with error checking:
#include <stdio.h>
int main() {
int x[100], y[100], i, j, dim1, dim2;
if (scanf("%d", &dim1) != 1 || dim1 > 100)
return 1;
for (i = 0; i < dim1; i++) {
if (scanf("%d", &x[i]) != 1)
return 1;
}
if (scanf("%d", &dim2) != 1 || dim2 > 100)
return 1;
/* no need to read second array if larger */
if (dim1 < dim2) {
printf("no\n");
return 0;
}
for (j = 0; j < dim2; j++) {
if (scanf("%d", &y[j]) != 1)
return 1;
}
/* trying every possible sub-array start in array `x` */
for (i = 0; i <= dim1 - dim2; i++) {
/* compare all entries */
for (j = 0; j < dim2; j++) {
if (x[i + j] != y[j])
break;
}
/* if above loop completed, we have a match */
if (j == dim2) {
printf("yes\n");
return 0;
}
}
printf("no\n");
return 0;
}

A possible implementation, based on your approach:
// this function will return `1` in case `arr2` is contained inside `arr1`, otherwise `0`
int is_subarr(int arr1[], size_t arr1_len, int arr2[], size_t arr2_len) {
// as you already did, we first check that arr1's len is not smaller than arr2's
if (arr1_len < arr2_len) {
return 0;
}
// useful check: in many implementations, when `arr2` is empty, they return true
if (arr2_len == 0) {
return 1;
}
// first loop: we go through all elements of `arr1` (but we stop when we have less elements left than `arr2`'s len)
for (size_t i = 0; i < arr1_len && i < arr2_len; i += 1) {
// temporary flag, we just pretend that `arr2` is contained, and then we check for the opposite
int eq = 1;
// starting with the current position `i` inside `arr1`, we start checking if `arr2` is contained
for (size_t j = 0; j < arr2_len; j += 1) {
// if it's not contained, we break from this inner loop, and we keep searching through `arr1`
if (arr1[i + j] != arr2[j]) {
eq = 0;
break;
}
}
// in case `arr2` is effectively found, we return `1`
if (eq == 1) {
return 1;
}
}
return 0;
}
NOTE: "strings of integers" are called "arrays of integers" in C; a "string" is an "array of chars", instead.

Related

How do I find duplicates of an int in an array in this case?

I am working on a school assignment and currently I'm a stuck on a part or it.
The piece of the program that I am showing further down, is supposed to take 7 numbers, check if they are above 0 and below maxValue, then, another function, checkIfContains should check if there are any duplicates in that array and return true or false to the first function, enterRow.
If everything is fine (numbers are within range and no duplicates), then nothing more is to be done by the functions here.. ( I have isolated these two. There are more where these came from, we are supposed to make a lottery game)
What am I doing wrong?
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
void enterRow(int numbers[], int len, int maxValue);
bool checkIfContains(int digit, int arrayToCheck[], int len);
int main(void)
{
int len = 7;
int maxValue = 39;
int numbers[len];
memset(numbers, 0, sizeof(int) * len);
enterRow(numbers, len, maxValue);
return 0;
}
void enterRow(int numbers[], int len, int maxValue)
{
int flag = 1;
printf("\nEnter your lotto row (%d values between 1-%d): ", len, maxValue);
do
{
for(int i = 0; i < len; i++) scanf(" %d", &numbers[i]);
for (int i = 0; i < len; i++)
{
if (numbers[i] < 1 || numbers[i] > maxValue)
{
printf("Numbers must be between 1-%d, try again!\n", maxValue);
break;
}
if (checkIfContains(numbers[i], numbers, len) == true)
{
printf("Duplicate, try again: ");
break;
}
else
{
flag = 2;
}
}
} while (flag == 1);
}
bool checkIfContains(int digit, int arrayToCheck[], int len)
{
for (int i = 1; i < len; i++)
{
if (arrayToCheck[i] == digit)
{
return true;
}
else
{
return false;
}
}
}
A few issues:
The check function will check the current value against itself, so the array will always have a duplicate
You only want to return false at the end of the loop
There is no return at the end of the function
Your loop was starting with 1 but needs to start with 0
To fix, rather than pass a match value, pass the index of the value.
Here's the refactored code:
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
void enterRow(int numbers[], int len, int maxValue);
bool checkIfContains(int curidx, int arrayToCheck[], int len);
int
main(void)
{
int len = 7;
int maxValue = 39;
int numbers[len];
memset(numbers, 0, sizeof(int) * len);
enterRow(numbers, len, maxValue);
return 0;
}
void
enterRow(int numbers[], int len, int maxValue)
{
int flag = 1;
printf("\nEnter your lotto row (%d values between 1-%d): ", len, maxValue);
do {
for (int i = 0; i < len; i++)
scanf(" %d", &numbers[i]);
for (int i = 0; i < len; i++) {
if (numbers[i] < 1 || numbers[i] > maxValue) {
printf("Numbers must be between 1-%d, try again!\n", maxValue);
break;
}
if (checkIfContains(i, numbers, len) == true) {
printf("Duplicate, try again: ");
break;
}
else {
flag = 2;
}
}
} while (flag == 1);
}
bool
checkIfContains(int curidx, int arrayToCheck[], int len)
{
int digit = arrayToCheck[curidx];
for (int i = 0; i < len; i++) {
// don't check number against itself
if (i == curidx)
continue;
if (arrayToCheck[i] == digit)
return true;
}
return false;
}
The function checkIfContains has two defects.
First of all the loop shall start from the next position of the element that is passed to the function as a value of the parameter digit. It means that the function should be called at least like like
if (checkIfContains(numbers[i], numbers + i + 1, len - i - 1 ) == true)
And within the function the for loop shall start from 0
for (int i = 0; i < len; i++)
instead of 1 as in your function
for (int i = 1; i < len; i++)
The second defect is that you shall not return false as soon as unequal element is found in the array.
Using your approach The function can look the following way
bool checkIfContains(int digit, const int arrayToCheck[], int len)
{
int i = 0;
while ( i < len && arrayToCheck[i] != digit ) ++i;
return i != len;
}
And as I already mentioned the function must be called like
if (checkIfContains(numbers[i], numbers + i + 1, len - i - 1 ) == true)
Though your approach too complicated. You could check entered values in the first for loop
for(int i = 0; i < len; i++)
{
scanf(" %d", &numbers[i]);
// 1) check whether the value is in the range
// 2) check whether the value is unique
//...
}
To check if there are duplicates in an array, the most basic way is to loop through the array using two nested for loops and compare each element with the others, like so:
int array[5] = {5, 7, 6, 3, 5};
int arrayLength = 5;
for(int i = 0; i < arrayLength; i++)
{
for(int j = i + 1; j < arrayLength; j++)
{
if(array[i] == array[j])
{
printf("%d has duplicate\n", array[i]);
}
}
}
You can make your code like:
bool hasDuplicate(int array[], int arrayLength)
{
for(int i = 0; i < arrayLength; i++)
{
for(int j = i + 1; j < arrayLength; j++)
{
if(array[i] == array[j])
{
return true;
}
}
}
return false;
}
And you can make enterRow like this:
void enterRow(int numbers[], int len, int maxValue)
{
printf("\nEnter your lotto row (%d values between 1-%d): ", len, maxValue);
for(int i = 0; i < len; i++)
scanf(" %d", &numbers[i]);
for(int i = 0; i < len; i++)
{
if(numbers[i] > maxValue || numbers[i] < 1)
{
printf("Format is not correct.\n");
while(1);
}
}
if(hasDuplicate(numbers, len) == true)
{
printf("The numbers cannot be duplicates.\n");
while(1);
}
}
This way your code is much cleaner and more readable. Obviously, you should optimize this code to how you want to deal with the error cases and etc.

Print elements of an array that appear only once (C)

I am having trouble achieving the wanted results. The program should ask for 20 inputs and then go over each to see if they appear more than once. Then only print out those that appeared once.
However currently my program prints out random numbers that are not inputted.
For example:
array = {10,10,11,12,10,10,10.....,10} should return 11 and 12
#include <stdio.h>
void main() {
int count, size=20, array[size], newArr[size];
int number=0;
for(count = 0; count < size; count++) {
// Ask user for input until 20 correct inputs.
printf("\nAnna %d. luku > ", count+1);
scanf("%d", &number);
if( (number > 100) || (number < 10) ) {
while(1) {
number = 0;
printf("Ei kelpaa.\n");//"Is not valid"
printf("Yrita uudelleen > ");//"Try again >"
scanf("%d", &number);
if ( (number <= 100) && (number >= 10) ) {
break;
}
}
}
array[count] = number;
}
for(int i=0; i < size; i++) {
for(int j=0; j<size; j++){
if(array[i] == array[j]){
size--;
break;
} else {
// if not duplicate add to the new array
newArr[i] == array[j];
}
}
}
// print out all the elements of the new array
for(int k=0; k<size; k++) {
printf("%d\n", newArr[k]);
}
}
You don't need the newArr here, or the separate output loop. Only keep a count that you reset to zero at the beginning of the outer loop, and increase in the inner loop if you find a duplicate.
Once the inner loop is finished, and the counter is 1 then you don't have any duplicates and you print the value.
In code perhaps something like:
for (unsigned i = 0; i < size; ++i)
{
unsigned counter = 0;
for (unsigned j = 0; j < size; ++j)
{
if (array[i] == array[j])
{
++counter;
}
}
if (counter == 1)
{
printf("%d\n", array[i]);
}
}
Note that the above is a pretty naive and brute-force way to deal with it, and that it will not perform very well for larger array sizes.
Then one could implement a hash-table, where the value is the key, and the count is the data.
Each time you read a value you increase the data for that value.
Once done iterate over the map and print all values whose data (counter) is 1.
Use functions!!
Use proper types for indexes (size_t).
void printdistinct(const int *arr, size_t size)
{
int dist;
for(size_t s = 0; s < size; s++)
{
int val = arr[s];
dist = 1;
for(size_t n = 0; n < size; n++)
{
if(s != n)
if(val == arr[n]) {dist = 0; break;}
}
if(dist) printf("%d ", val);
}
printf("\n");
}
int main(void)
{
int test[] = {10,10,11,12,10,10,10,10};
printdistinct(test, sizeof(test)/sizeof(test[0]));
fflush(stdout);
}
https://godbolt.org/z/5bKfdn9Wv
This is how I did it and it should work for your:
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <stdarg.h>
void printdistinct(const int *muis, size_t size);
int main()
{
int loop=20,i,muis[20],monesko=0;
for(i=0; i<loop; i++){
monesko++;
printf ("Anna %d. luku: \n",monesko);
scanf("%d", &muis[i]);
if (muis[i]<10 || muis[i]>100){
printf("Ei kelpaa!\n");
muis[i] = muis[i + 1];
printf("YRITÄ UUDELLEEN:\n ");
scanf("%d", &muis[i]);
}
}
printdistinct(muis, sizeof(muis)/sizeof(muis[0]));
fflush(stdout);
return 0;
}
void printdistinct(const int *muis, size_t size)
{
for(size_t s = 0; s < size; s++)
{
int a = muis[s];
int testi = 1;
for(size_t n = 0; n < size; n++){
if(s != n) {
if(a == muis[n]){
testi = 0;
break;
}
}
}
if(testi) {
printf("%d \n", a);
}
testi = 1;
}
printf("\n");
}
This approach uses some memory to keep track of which elements are duplicates. The memory cost is higher, but the processor time cost is lower. These differences will become significant at higher values of size.
char* duplicate = calloc(size, 1); // values are initialized to zero
for (unsigned i = 0; i < size; ++i)
{
if(!duplicate[i]) // skip any value that's known to be a duplicate
{
for (unsigned j = i + 1; j < size; ++j) // only look at following values
{
if (array[i] == array[j])
{
duplicate[i] = 1;
duplicate[j] = 1; // all duplicates will be marked
}
}
if (!duplicate[i])
{
printf("%d\n", array[i]);
}
}
}
What you can do is you can initialize a hashmap that will help you store the unique elements. Once you start iterating the array you check for that element in the hashmap. If it is not present in the hashmap add it to the hashmap. If it is already present keep iterating.
This way you would not have to iterate the loop twice. Your time complexity of the algorithm will be O(n).
unordered_map < int, int > map;
for (int i = 0; i < size; i++) {
// Check if present in the hashmap
if (map.find(arr[i]) == map.end()) {
// Insert the element in the hash map
map[arr[i]] = arr[i];
cout << arr[i] << " ";
}
}

Finding duplicate value in a row (2D array)

I would like to know how to find duplicate values in the 1st row of my 2d array.
I thought that by setting array[0][0] == array[i][j], it would check if the array[0][0] equals to the number of array[0][rest of the column]. But my code is just popping up my try again message whenever I put my first value.
Here's what I've tried so far.
void main(void)
{
int array[2][5];
int i, j, l, k;
printf("\Please enter 10 values\n");
for (j = 0; j < 5; j++)
{
for (i = 0; i < 2; i++)
{
scanf("%i", &array[i][j]);
for (k = 0; k < 2; k++)
{
for (l = 0; l < 5; l++)
{
while (array[0][0] == array[i][j])
{
printf("You entered 2 identical numbers in the first row, try again:\n");
scanf("%i", &array[i][j]);
}
}
}
}
}
}
// this isn't the fastest algorithm but it works because of the small length
int check_duplicates(int arr[], int len) {
// iterate through the array
for (int i = 0; i < len; i++) {
// only need to check to the right
// since the left elements have been checked previously
for (int j = i + 1; j < len; j++) {
if (arr[i] == arr[j]) {
// there's a duplicate, return
return 1;
}
}
}
// no duplicates found
return 0;
}
int main(void) {
int array[2][5];
int i, j, l, k;
printf("Please enter 10 values\n");
for (j = 0; j < 5; j++) {
for (i = 0; i < 2; i++) {
scanf("%i", &array[i][j]);
// a duplicate has been found
if (check_duplicates(array[0], j + 1)) {
printf("You entered a duplicate, try again.\n");
// undo one loop to read back into that position
i --;
}
}
}
return 0;
}

Input sequence contained in an array

I'm trying to implement this excercise but it doesn't work very well. It should tell me if the sequence in array B is contained in A. Any ideas? I have a problem getting it to work for every sequence.
#include <stdio.h>
#include <stdlib.h>
#define N 6
#define M 3
int contains(int v[], int n);
/*
*
*/
int main(int argc, char** argv)
{
int A[N], B[M];
int i, j = 0, flag = 0, contained = 1;
printf("Array A\n");
for (i = 0; i < N; i++)
{
printf("Insert element: ");
scanf("%d", &A[i]);
}
printf("Array B\n");
for (i = 0; i < M; i++)
{
printf("Insert element: ");
scanf("%d", &B[i]);
}
for (i = 0; i < (N - M + 1); i++)
{
flag = 0;
if (A[i] == B[j])
{
flag = 1;
j++;
}
if (flag == 0 && (i == N-M))
{
contained = 0;
printf("The sequence B is not contained in A!\n");
break;
}
}
if (contained == 1)
{
printf("The sequence B is contained in A\n");
}
return (EXIT_SUCCESS);
}
When you have a non match in the sequence, you never reset j so you start looking for the rest of the sequence starting to what ever value j was left at. Your program looks for the sequence B but doesn't require it to be contiguous.
You also don't check for when the sequence is completed so it for example B is at the start of A the j will keep incrementing and B[j] will overflow into unknown memory which is unlikely to match A so will give you an incorrect result. To fix this just check for when the whole of B is found and exit the loop.
Substituting the following will fix this:
if (j == M) break; // Break the loop when B sequence is found
if (flag == 0)
{
j = 0; // This was missing
if (i == N-M)
{
contained = 0;
printf("The sequence B is not contained in A!\n");
break;
}
}
For the third for loop when you're doing the check, you're (1) not actually checking every element of B against the corresponding element of A and (2) not checking the different start indices. What you probably meant to do is something like
for (i = 0; i < (N - M + 1); i++) {
for (j = 0; j < M; j++) {
if (A[i + j] != B[j]) {
break;
}
}
if (j == M) {
printf("Found a match!");
}
}
as your spinning through A if you find that an element of B does not match A then you need to set j back to 0
for (i = 0; i < (N - M + 1); i++)
{
int j;
for(j = 0; j < M; j++)
{
if(B[j] != A[j + i])
break;
}
/* sequence found */
if(j == M)
{
return true;
}
}
return false;
For searching B in A you may want to do something like following:
for (i = 0; i < (N - M + 1) ; i++)
if (A[i] == B[0])
{ j=0;
while (A[++i] == B[++j] && j<M);
break;
}
if (j == M)
{
printf("The sequence B is contained in A\n");
}
else{
printf("The sequence B is not contained in A\n");
}
GCC has the memmem() extention function (which is basically strstr(), but does not rely on NUL-terminated strings)
if (memmem(A, N * sizeof *A, B, M * sizeof *B)) {
printf("Found\n" );
} else {
printf("Not Found\n" );
}

removing duplicate integers from an array in C

I am working on a program that removes duplicate values from an array by ordering it and then removing duplicate, consecutive values. First I execute a selection sort sorting method, and then call a function removedup() that modifies the array and returns the size. Then I basically print the values in the array up to that size. However, when I execute it, it only prints the original array and then a bunch of blank space. Does anyone know why this is occurring?
My code: http://pastebin.com/uTTnnMHN
Just the de-duplication code:
int removedup(int a[])
{
int i, count, j;
count = n;
for (i = 0; i < (n - 1); i++) {
if (a[i] == a[i + 1]) {
for (j = 0; j < (n - i); j++) {
a[j] = a[j + 1];
}
count--;
i--;
}
}
return count;
}
-1 for(j=0;j<(n-i);j++)
Is your loop to shift left your array (thus removing the duplicate value), j should not be init to j but to i, and the condition does not seem right
A correct one could be:
for(j=i;j<n-1;j++)
{
a[j]=a[j+1];
}
a[n-1] = 0; // Because you shift your table to the left, the last value should not be used
first if i=0 and if a[i]==a[i+1] then i=-1
for(i=0;i<(n-1);i++)
{
if(a[i]==a[i+1])
{
for(j=0;j<(n-i);j++)
{
a[j]=a[j+1];
}
count--;
i--; //i=-1 if(a[i]==a[i+1]) && if(i==0)
}
}
In your duplicate removal function, you need to start the moving loop at i, as has been mentioned, and you must use count - 1 as the loop bound for both loops, otherwise you will have an infinite loop whenever there are duplicates, because then a[n-2] == a[n-1] always after the first moving loop.
int removedup(int a[])
{
int i, count, j;
count = n;
for(i = 0; i < (count-1); i++)
{
if(a[i] == a[i+1])
{
for(j = i; j < (count-1); j++)
{
a[j]=a[j+1];
}
count--;
i--;
}
}
return count;
}
works correctly.
Since you're creating another array anyway, why not simplify your function?
int removedup(int a[], int b[])
{
int i;
int count = 1;
b[0] = a[0]
for(i=1;i<(n-1);i++){
if(a[i-1] != a[i]){
b[count++] = a[i];
}
}
return count;
}
Then when you call the function,
count=removedup(a, OutArray);
int removedup(int a[])
{
int i;
count = n;
for (i = 0; i < (count-1); ++i) {
if (a[i] == a[i+1]) { /* found a duplicate */
int d = 0; /* count the duplicates */
do {
++d;
} while ((i+1+d) < count && a[i] == a[i+1+d]); /* probe ahead again for a duplicate */
/* at this point we have either run out of duplicates or hit the end of the array */
if ((i+1+d) < count)
memmove(&a[i+1], &a[i+1+d], sizeof(int)*(count-(i+1+d))); /* shift down rest of the array if there's still elements to look at */
count -= d; /* adjust the count down by the number of duplicates */
}
}
return count;
}
what about this one,without sort but traverse.finally print the effective values of the array and return its size.
int removedup(int a[])
{
int i, count, j;
count = n;
int b[n];
memset(b,0,sizeof(b));
for (i = 0; i < (n - 1); i++)
{
if (-1 != b[i])
{
for(j=i+1;j<n-1;j++)
{
if( a[i]==a[j])
{
b[j]=-1;
count--;
}
}
}
}
for(i=0;i<n-1;i++)
{
if(-1 != b[i])
{
printf("%d ",a[i]);
}
}
return count;
}

Resources