Suppose that we have a string "11222222345646". So how to print out subsequence 222222 in C.
I have a function here, but I think something incorrect. Can someone correct it for me?
int *longestsubstring(int a[], int n, int *length)
{
int location = 0;
length = 0;
int i, j;
for (i = 0, j = 0; i <= n-1, j < i; i++, j++)
{
if (a[i] != a[j])
{
if (i - j >= *length)
{
*length = i - j;
location = j;
}
j = i;
}
}
return &a[location];
}
Sorry,I don't really understand your question.
I just have a little code,and it can print the longest sub string,hope it can help.
/*breif : print the longest sub string*/
void printLongestSubString(const char * str,int length)
{
if(length <= 0)
return;
int i ;
int num1 = 0,num2 = 0;
int location = 0;
for(i = 0; i< length - 1; ++i)
{
if(str[i] == str[i+1])
++num2;//count the sub string ,may be not the longest,but we should try.
else
{
if(num2 >num1)//I use num1 store the sum longest of current sub string.
{ num1 = num2;location = i - num2;}
else
;//do nothing for short sub string.
num2 = 0;
}
}
for(i = location;str[i]== str[num1];++i)
printf("%c",str[i]);
printf("\n");
}
int main()
{
char * str = "1122222234566";
printLongestSubString(str,13);
return 0;
}
From your code it appears you want to return the longest sub-sequence (sub-string). Since I'm relearning C I thought I would give it a shot.
I've used strndup to extract the substring. I'm not sure how portable it is but I found an implementation if needed, just click on the link. It will allocate memory to store the new cstring so you have to remember to free the memory once finished with the substring. Following your argument list, the length of the sub-string is returned as the third argument of the extraction routine.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char *extract_longest_subsequence(const char *str, size_t str_len, size_t *longest_len);
int main()
{
char str[] = "11222234555555564666666";
size_t substr_len = 0;
char *substr = extract_longest_subsequence(str, sizeof(str), &substr_len);
if (!substr)
{
printf("Error: NULL sub-string returned\n");
return 1;
}
printf("original string: %s, length: %zu\n", str, sizeof(str)-1);
printf("Longest sub-string: %s, length: %zu\n", substr, substr_len);
/* Have to remember to free the memory allocated by strndup */
free(substr);
return 0;
}
char *extract_longest_subsequence(const char *str, size_t str_len, size_t *longest_len)
{
if (str == NULL || str_len < 1 || longest_len == NULL)
return NULL;
size_t longest_start = 0;
*longest_len = 0;
size_t curr_len = 1;
size_t i = 0;
for (i = 1; i < str_len; ++i)
{
if (str[i-1] == str[i])
{
++curr_len;
}
else
{
if (curr_len > *longest_len)
{
longest_start = i - curr_len;
*longest_len = curr_len;
}
curr_len = 1;
}
}
/* strndup allocates memory for storing the substring */
return strndup(str + longest_start, *longest_len);
}
It looks like in your loop that j is supposed to be storing where the current "substring" starts, and i is the index of the character that you are currently looking at. In that case, you want to change
for (i = 0, j = 0; i <= n-1, j < i; i++, j++)
to
for (i = 0, j = 0; i <= n-1; i++)
That way, you are using i to store which character you're looking at, and the j = i line will "reset" which string of characters you are checking the length of.
Also, a few other things:
1) length = 0 should be *length = 0. You probably don't actually want to set the pointer to point to address 0x0.
2) That last line would return where your "largest substring" starts, but it doesn't truncate where the characters start to change (i.e. the resulting string isn't necessarily *length long). It can be intentional depending on use case, but figured I'd mention it in case it saves some grief.
Related
The problem: After the convert_tolower(words) function is completed I want to add a new word in the words array( if the words array has less than 5 words)..But I am getting either errors or unexpected results(e.g some weird characters being printed)...What i thought is shifting the elements of the words array and then work with pointers because I am dealing with strings.But I am having quite some trouble achieving that..Probably the problem is in lines
35-37
How I want the program to behave:
Get 5 words(strings) at most from user input
Take these strings and place them in an array words
Convert the elements of the array to lowercase letters
After the above,ask the user again to enter a new word and pick the position of that word.If the words array already has 5 words then the new word is not added.Else,the new word is added in the position the user chose.(The other words are not deleted,they are just 'shifted').
Also by words[1] I refer to the first word of the words array in its entirety
The code:
#include <stdio.h>
#include <string.h>
#define W 5
#define N 10
void convert_tolower(char matrix[W][N]);
int main() {
int j = 0;
int i = 0;
int len = 0;
char words[W][N] = {{}};
char test[W][N];
char endword[N] = "end";
char newword[N];
int position;
while (scanf("%9s", test), strcmp(test, endword)) {
strcpy(words[i++], test);
j++;
len++;
if (j == W) {
break;
}
}
convert_tolower(words);
printf("Add a new word\n");
scanf("%9s", newword);
printf("\nPick the position\n");
scanf("%d",position);
if (len < W) {
for (i = 0; i < W-1; i++) {
strcpy(words[i], words[i + 1]); /*Shift the words */
words[position] = newword;
}
}
for (i = 0; i < W; i++) {
printf("%s", words[i]);
printf("\n");
}
printf("End of program");
return 0;
}
void convert_tolower(char matrix[W][N]) {
int i;
int j;
for (i = 0; i < W; i++) {
for (j = 0; j < N; j++) {
matrix[i][j] = tolower(matrix[i][j]);
}
}
}
This initialization
char words[W][N] = {{}};
is incorrect in C. If you want to zero initialize the array then just write for example
char words[W][N] = { 0 };
In the condition of the while loop
while (scanf("%9s", test), strcmp(test, endword)) {
there is used the comma operator. Moreover you are using incorrectly the two-dimensional array test instead of a one-dimensional array
It seems you mean
char test[N];
//...
while ( scanf("%9s", test) == 1 && strcmp(test, endword) != 0 ) {
And there are used redundantly too many variables like i, j and len.
The loop could be written simpler like
char test[N];
//...
for ( ; len < W && scanf("%9s", test) == 1 && strcmp(test, endword) != 0; ++len )
{
strcpy(words[len], test);
}
In this call
scanf("%d",position);
there is a typo. You must to write
scanf("%d", &position);
Also you should check whether the entered value of position is in the range [0, len].
For example
position = -1;
printf("\nPick the position\n");
scanf("%d", &position);
if ( len < W && -1 < position && position <= len ) {
Also this for loop
for (i = 0; i < W-1; i++) {
strcpy(words[i], words[i + 1]); /*Shift the words */
words[position] = newword;
}
does not make a sense. And moreover this assignment statement
words[position] = newword;
is invalid. Arrays do not have the assignment operator.
You need to move all strings starting from the specified position to the right.
For example
for ( i = len; i != position; --i )
{
strcpy( words[i], words[i-1] );
}
strcpy( words[position], newword );
++len;
And it seems the function convert_tolower should be called for the result array after inserting a new word. And moreover you need to pass the number of actual words in the array.
convert_tolower(words, len);
The nested loops within the function convert_tolower should look at least the following way
void convert_tolower(char matrix[][N], int n) {
int i;
int j;
for (i = 0; i < n; i++) {
for (j = 0; matrix[i][j] != '\0'; j++) {
matrix[i][j] = tolower(( unsigned char )matrix[i][j]);
}
}
}
The main problem with your code was initially that you declared char *words[W][N], then tried to insert strings into this 2d array of pointers. Sparse use of organizing functions, and variables with large scopes than necessary made it hard to read. I think the best way to help you is to show you a working minimal implementation. Step 4 is not sufficiently specified. insert currently shift. It is not clear what should happen if you insert at position after empty slots, or if insert a position before empty slots and in particular if there are non-empty slots after said position.
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#define W 5
#define N 10
void convert(size_t w, size_t n, char list[][n]) {
for(size_t i = 0; i < w; i++) {
for(size_t j = 0; j < n; j++) {
list[i][j] = tolower(list[i][j]);
}
}
}
void insert(size_t w, size_t n, char list[][n], size_t pos, char *word) {
// out out of bounds
if(pos + 1 > w) return;
// shift pos through w - 2 pos
for(size_t i = w - 2; i >= pos; i--) {
strcpy(list[i + 1], list[i]);
if(!i) break;
}
// insert word at pos
strcpy(list[pos], word);
}
void print(size_t w, size_t n, char list[][n]) {
for (size_t i = 0; i < w; i++) {
printf("%u: %s\n", i, list[i]);
}
}
int main() {
char words[W][N] = { "a", "BB", "c" };
convert(W, N, words);
insert(W, N, words, 0, "start");
insert(W, N, words, 2, "mid");
insert(W, N, words, 4, "end");
insert(W, N, words, 5, "error")
print(W, N, words);
return 0;
}
and the output (note: "c" was shifted out as we initially had 3 elements and added 3 new words with valid positions):
0: start
1: a
2: mid
3: bb
4: end
Let's say I have a series of data that's in this form:
"SomethingIDontCareAbout : SomethingICareAbout"
where the part after the ":" can vary in length of course.
The goal here is only storing the "SomethingICareAbout" substring efficiently. I made this function but the problem is that I'm storing both substrings,so it seems like a waste of memory. Any help to reduce to the time/space complexity?
char** ExtractKey(char* S)
{
int n = strlen(S);
int count = 0, i = 0, j = 0;
for(i = 0; i < n; i++)
{
if(S[i] == ':')
break;
count++;
}
char** T = (char**)malloc(2 * sizeof(char*));
T[0] = (char*)malloc((count + 1) * sizeof(char));
T[1] = (char*)malloc((n - count) * sizeof(char));
for(i = 0; i < count; i++) // inefficient ? cus we won't need T[0] [j]
{
T[0][j] = S[i];
j++;
}
T[0][j+1] = '\0';
j = 0;
for(i = count + 1; i < n; i++)
{
T[1][j] = S[i];
j++;
}
T[1][j+1] = '\0';
return T;
}
There is no reason to invent a search for a character in a string, or a copy of a string.
If the input data will live long enough for you to use the "value" part, just return a pointer to the value:
char* ExtractKey(char* S)
{
return strchr(S, ':');
}
If it doesn't, or if you for some reason need a separate copy:
char* ExtractKey(char* S)
{
return strdup(strchr(S, ':'));
}
Honestly, this could be done efficiently if strtok() was used to split those strings. I have designed the following code that parses each string of a 2-D array with a common delimiter that is : here.
Now, let's take a look into the code (notice the comments):
#include <stdio.h>
#include <string.h>
#define MAX_LEN 128
int main(void) {
// The 2-D string
char str[][MAX_LEN] = {"SomethingElse : SomethingToCareAbout",
"Something2 : SomethingToCare2",
"Unnecessary : Necessary"};
int size = sizeof(str) / sizeof(str[0]);
// Applying Variable-Length Array (valid in C)
char store_cared_ones[size][MAX_LEN];
for (int i = 0; i < size; i++) {
// Declaring a temporary pointer variable to obtain the required
// substring from each string
char *sub_str = NULL;
sub_str = strtok(str[i], ": ");
sub_str = strtok(NULL, ": ");
// Copying the 'sub_str' into each array element of 'store_cared_ones'
strcpy(store_cared_ones[i], sub_str);
}
// Displaying each of 'store_cared_ones'
for (int i = 0; i < size; i++)
fprintf(stdout, "%s\n", store_cared_ones[i]);
return 0;
}
Finally, let's see what that code does:
rohanbari#genesis:~/stack$ ./a.out
SomethingToCareAbout
SomethingToCare2
Necessary
I need help to understand an issue with my C code. I am trying to find longest substring within a given string without character repetition. When run on the leetcode platform, the code below gives me an error for the String "amqpcsrumjjufpu":
Runtime Error Message: Line 17: index -3 out of bounds for type 'int [256]'
However, the same code works fine when I run it from my computer or any online editor. Please help me to understand this behaviour difference.
#include <stdio.h>
#include <string.h>
int lengthOfLongestSubstring(char* s) {
char *h = s;
int A[256] = {0};
int length = 0;
int temp = 0;
int max = 0;
int len = strlen(s);
for(int i = 0; i < len;i ++){
int A[256] = {0};
length = 0;
h = s + i;
for(int j = i; j < len-1; j++){
if (A[h[j]] == 1) {
break;
} else {
A[h[j]] = 1;
length +=1;
}
if (max < length) {
max = length;
}
}
}
return max;
}
int main() {
char *s = "amqpcsrumjjufpu";
int ret = lengthOfLongestSubstring(s);
printf("SAURABH: %d",ret);
}
It seems you are trying to write a function that finds the length of the longest substring of unique characters.
For starters the function should be declared like
size_t lengthOfLongestSubstring( const char *s );
^^^^^^ ^^^^^
These declarations in the outer scope of the function
int A[256] = {0};
//...
int temp = 0;
are redundant. The variables are not used in the function.
The type char can behave either as the type signed char or the type unsigned char. So in expressions like this A[h[j]] you have to cast explicitly the character used as index to the type unsigned char as for example
A[( unsigned char )h[j]]
The inner loop
for(int j=i;j<len-1;j++){
will not execute for strings that contain only one character. So it does not make sense as it is written.
This if statement
if (max < length) {
max = length ;
}
needs to be placed outside the inner loop.
The algorithm used by you can be implemented the following way
#include <stdio.h>
#include <limits.h>
size_t lengthOfLongestSubstring(const char *s)
{
size_t longest = 0;
for (; *s; ++s )
{
size_t n = 0;
unsigned char letters[UCHAR_MAX] = { 0 };
for ( const char *p = s; *p && !letters[(unsigned char)*p - 1]++; ++p) ++n;
if (longest < n) longest = n;
}
return longest;
}
int main( void )
{
char *s = "123145";
printf("The longest substring has %zu characters.\n",
lengthOfLongestSubstring(s));
return 0;
}
The program output is
The longest substring has 5 characters.
Your code crashed because you read data out of range, suppose your input string is amqpcsrumjjufpu its length is 15, in outer loop for i = 13 you do assigment
h = s + i; // h was updated to indicate to 13th element of s
and in inner loop for first iteration, you read this element (j == i == 13)
A[h[j]]
so, you try to read this element A[*(h+j)], but h indicates to 13th element of s, and now you try to add 13 to this value, you want to read 26th position of s, you are out of range of s string.
Thanks Everyone for responses. While Vlad's code worked for all the test cases, here is my code that also passed all the test cases after changes suggested by Vlad and rafix.
int lengthOfLongestSubstring(char* s) {
char *h = s;
int max = 0;
int len = strlen(s);
if (len == 1) {
return 1;
}
for(int i = 0; i < len;i ++){
int A[256] = {0};
int length = 0;
for(int j = i; j < len; j++){
if (A[(unsigned char)h[j]] == 1) {
break;
} else {
A[(unsigned char) h[j]] = 1;
length +=1;
}
}
if (max < length) {
max = length;
}
}
return max;
}
I have created a function that should find the numerical position of the first character of a substring in a larger string. I am having some problems with the output and I am not too sure why. These problems include -1 being returned every single time instead of the integer position of the substring. I have debugged and cannot trace where the function goes wrong.
This is how the function should perform: If my string is "The dog was fast" and I am searching for the substring "dog", the function should return 4. Thanks to chqrlie for help with the loop.
Here is the function:
int findSubString(char original[], char toFind[]) {
size_t i, j;
int originalLength = 0;
int toFindLength = 0;
originalLength = strlen(original) + 1;
toFindLength = strlen(toFind) + 1;
for (i = 0; i < toFindLength + 1; i++) {
for (j = 0; j < originalLength + 1; j++) {
if (toFind[j] == '\0') {
return i;
}
if (original[i + j] != toFind[j]) {
break;
}
}
if (original[i] == '\0') {
return -1;
}
}
}
The function parameters cannot be modified, this is a requirement. Any help appreciated!
These statements inside the loops
if (toFind[j] == '\0') {
return i;
}
results in undefined behavior because the string toFind can be shorter than the string original.
The same is valid for this loop
if (original[i + j] != toFind[j]) {
break;
}
because i + j can be greater than the length of the string original.
And there is no need to scan all characters of the string original if you are going to find a substring inside it.
Also you should check whether the length of the string original is not less than the length of the string toFind.
If you want to find only the first character of the string toFind in the string original it is enough to use standard C function strchr. If you want to find the whole string toFind in the string original then you could use another C standard function strstr.
If you want to write the function yourself to find a string in other string then it can look for example the following way
I declared the function like
long long int findSubString( const char original[], const char toFind[] );
however you can write its declaration as you like for example like
int findSubString( char original[], char toFind[] );
But in this case you should declare function local variable success like
int success = -1;
and output the result using format specifier "%d" instead of "%lld".
Here you are.
#include <stdio.h>
#include <string.h>
#include <stddef.h>
long long int findSubString( const char original[], const char toFind[] )
{
size_t n = strlen( original );
size_t m = strlen( toFind );
long long int success = -1;
if ( !( n < m ) )
{
n = n - m + 1;
for ( size_t i = 0; success == -1 && i < n; i++ )
{
size_t j = 0;
while ( j < m && original[i+j] == toFind[j] ) j++;
if ( j == m ) success = i;
}
}
return success;
}
int main(void)
{
printf( "%lld\n", findSubString( "The dog was fast", "dog" ) );
return 0;
}
Its output is
4
Your loops are reversed. The outer loop should walk positions from zero to originalLength, inclusive; the nested loop should walk positions from zero to toFindLength, inclusive.
Both originalLength and toFindLength should be set to values returned by strlen, not strlen plus one, because null terminator position is not a good start.
Finally, you are returning -1 from inside the outer loop. This is too early - you should be returning -1 only after you are done with the outer loop as well.
Your loop counter tests are incorrect: wrong upper limit and the limits are off by one. Note that the tests are actually not necessary as you exit both loops when hitting the '\0' terminators.
Here is a simpler version:
int findSubString(const char *original, const char *toFind) {
for (size_t i = 0;; i++) {
for (size_t j = 0;; j++) {
if (toFind[j] == '\0') {
return i;
}
if (original[i + j] != toFind[j]) {
break;
}
}
if (original[i] == '\0') {
return -1;
}
}
}
There is a small advantage at computing the string lengths to reduce the number of comparisons in pathological cases such as findSubString("aaaaaaaaaaa", "aaaaaaaaaaaa");
int findSubString(const char *original, const char *toFind) {
size_t originalLength = strlen(original);
size_t toFindLength = strlen(toFind);
if (toFindLength <= originalLength) {
for (size_t i = 0; i <= originalLength - toFindLength; i++) {
for (size_t j = 0;; j++) {
if (toFind[j] == '\0') {
return i;
}
if (original[i + j] != toFind[j]) {
break;
}
}
}
}
return -1;
}
I have created a function that should find the numerical position of the first character of a substring in a larger string. I am having some problems with the output and I am not too sure why. These problems include -1 being returned every single time instead of the integer position of the substring. I have debugged and cannot trace where the function goes wrong.
This is how the function should perform: If my string is "The dog was fast" and I am searching for the substring "dog", the function should return 4. Thanks to chqrlie for help with the loop.
Here is the function:
int findSubString(char original[], char toFind[]) {
size_t i, j;
int originalLength = 0;
int toFindLength = 0;
originalLength = strlen(original) + 1;
toFindLength = strlen(toFind) + 1;
for (i = 0; i < toFindLength + 1; i++) {
for (j = 0; j < originalLength + 1; j++) {
if (toFind[j] == '\0') {
return i;
}
if (original[i + j] != toFind[j]) {
break;
}
}
if (original[i] == '\0') {
return -1;
}
}
}
The function parameters cannot be modified, this is a requirement. Any help appreciated!
These statements inside the loops
if (toFind[j] == '\0') {
return i;
}
results in undefined behavior because the string toFind can be shorter than the string original.
The same is valid for this loop
if (original[i + j] != toFind[j]) {
break;
}
because i + j can be greater than the length of the string original.
And there is no need to scan all characters of the string original if you are going to find a substring inside it.
Also you should check whether the length of the string original is not less than the length of the string toFind.
If you want to find only the first character of the string toFind in the string original it is enough to use standard C function strchr. If you want to find the whole string toFind in the string original then you could use another C standard function strstr.
If you want to write the function yourself to find a string in other string then it can look for example the following way
I declared the function like
long long int findSubString( const char original[], const char toFind[] );
however you can write its declaration as you like for example like
int findSubString( char original[], char toFind[] );
But in this case you should declare function local variable success like
int success = -1;
and output the result using format specifier "%d" instead of "%lld".
Here you are.
#include <stdio.h>
#include <string.h>
#include <stddef.h>
long long int findSubString( const char original[], const char toFind[] )
{
size_t n = strlen( original );
size_t m = strlen( toFind );
long long int success = -1;
if ( !( n < m ) )
{
n = n - m + 1;
for ( size_t i = 0; success == -1 && i < n; i++ )
{
size_t j = 0;
while ( j < m && original[i+j] == toFind[j] ) j++;
if ( j == m ) success = i;
}
}
return success;
}
int main(void)
{
printf( "%lld\n", findSubString( "The dog was fast", "dog" ) );
return 0;
}
Its output is
4
Your loops are reversed. The outer loop should walk positions from zero to originalLength, inclusive; the nested loop should walk positions from zero to toFindLength, inclusive.
Both originalLength and toFindLength should be set to values returned by strlen, not strlen plus one, because null terminator position is not a good start.
Finally, you are returning -1 from inside the outer loop. This is too early - you should be returning -1 only after you are done with the outer loop as well.
Your loop counter tests are incorrect: wrong upper limit and the limits are off by one. Note that the tests are actually not necessary as you exit both loops when hitting the '\0' terminators.
Here is a simpler version:
int findSubString(const char *original, const char *toFind) {
for (size_t i = 0;; i++) {
for (size_t j = 0;; j++) {
if (toFind[j] == '\0') {
return i;
}
if (original[i + j] != toFind[j]) {
break;
}
}
if (original[i] == '\0') {
return -1;
}
}
}
There is a small advantage at computing the string lengths to reduce the number of comparisons in pathological cases such as findSubString("aaaaaaaaaaa", "aaaaaaaaaaaa");
int findSubString(const char *original, const char *toFind) {
size_t originalLength = strlen(original);
size_t toFindLength = strlen(toFind);
if (toFindLength <= originalLength) {
for (size_t i = 0; i <= originalLength - toFindLength; i++) {
for (size_t j = 0;; j++) {
if (toFind[j] == '\0') {
return i;
}
if (original[i + j] != toFind[j]) {
break;
}
}
}
}
return -1;
}