Below is a code sample for a function that removes similar adjacent characters in a string. For a given arguement like remove_adjacent("azyyzb"), the expected output should be ab, since it should first remove adjacent characters yy to get substring azzb. It should then remove adjacent characters zz in the substring, to finally get substring ab. However, my function only handles the first adjacent characters, and fails to handle the second part. It could be an indication that it is not looping as expected. Could someone point out what the problem might be?
public static void remove_adjacent(String str1)
{
int i = 0;
do
{
int j = i + 1;
if (str1.charAt(i) == str1.charAt(j))
str1 = str1.substring(0, i) + str1.substring(j + 1, str1.length());
i++;
}
while (i < str1.length() - 1);
System.out.println(str1);
}
Because your i is already pointing at index 2 when you remove yy. But your first z is at index 1, which won't be checked anymore.
When you remove a part of the string, you will need to go one position backwards in your string to check, if a new pair of equal characters was created. And you must only step forward, if nothing was removed in the current iteration.
public static void remove_adjacent(String str1)
{
int i = 0;
do
{
int j = i + 1;
if (str1.charAt(i) == str1.charAt(j)) {
str1 = str1.substring(0, i) + str1.substring(j + 1, str1.length());
if (i > 0) i--;
} else {
i++;
}
}
while (i < str1.length() - 1);
System.out.println(str1);
}
Related
I was doing an exercise from LeetCode in which consisted in deleting any adjacent elements from a string, until there are only unique characters adjacent to each other. With some help I could make a code that can solve most testcases, but the string length can be up to 10^5, and in a testcase it exceeds the time limit, so I'm in need in some tips on how can I optimize it.
My code:
char res[100000]; //up to 10^5
char * removeDuplicates(char * s){
//int that verifies if any char from the string can be deleted
int ver = 0;
//do while loop that reiterates to eliminate the duplicates
do {
int lenght = strlen(s);
int j = 0;
ver = 0;
//for loop that if there are duplicates adds one to ver and deletes the duplicate
for (int i = 0; i < lenght ; i++){
if (s[i] == s[i + 1]){
i++;
j--;
ver++;
}
else {
res[j] = s[i];
}
j++;
}
//copying the res string into the s to redo the loop if necessary
strcpy(s,res);
//clar the res string
memset(res, '\0', sizeof res);
} while (ver > 0);
return s;
}
The code can't pass a speed test that has a string that has around the limit (10^5) length, I won't put it here because it's a really big text, but if you want to check it, it is the 104 testcase from the LeetCode Daily Problem
If it was me doing something like that, I would basically do it like a simple naive string copy, but keep track of the last character copied and if the next character to copy is the same as the last then skip it.
Perhaps something like this:
char result[1000]; // Assumes no input string will be longer than this
unsigned source_index; // Index into the source string
unsigned dest_index; // Index into the destination (result) string
// Always copy the first character
result[0] = source_string[0];
// Start with 1 for source index, since we already copies the first character
for (source_index = 1, dest_index = 0; source_string[source_index] != '\0'; ++source_index)
{
if (source_string[source_index] != result[dest_index])
{
// Next character is not equal to last character copied
// That means we can copy this character
result[++dest_index] = source_string[source_index];
}
// Else: Current source character was equal to last copied character
}
// Terminate the destination string
result[dest_index + 1] = '\0';
I am working on an anagram solver in C. Hit a problem where the solver will return the first few anagrams correctly, however on ones that extend past 2 words, it begins to enter an infinite loop.
Example:
I enter "team sale rest" into the anagram solver, it responds with teamster ale, and a few others. Then when it arrives at releases, it enters an infinite loop where it prints "releases am matt" "releases am am matt" etc.
Here is the code base:
//recursively find matches for each sub-word
int findMatches(char string[], char found_so_far[])
{
printf("String entering function: %s\n", string);
int string_length = strlen(string);
int_char_ptr *results = getPowerSet(string, string_length);
if(!results)
return 2;
// selects length of subset, starting with the largest
for (int i = string_length - 1; i > 0; i--)
{
// iterates through all the subsets of a particular length
for(int j = 0; j < results->count[i]; j++)
{
word_array *matches = NULL;
// check words against dictionary
matches = dictionary_check(results->table[i][j]);
if (matches)
{
// iterate through matches
for(size_t k = 0; k < matches->size; k++)
{
int found_length;
// find out length of string needed for found
if (strcmp(found_so_far, "") == 0)
found_length = strlen(matches->arr[k]) + 1;
else
found_length = strlen(found_so_far) + strlen(matches->arr[k]) + 2;
char found[found_length];
// on first passthrough, copy directly from matches
if (strcmp(found_so_far, "") == 0)
strcpy(found, matches->arr[k]);
else
sprintf(found, "%s %s", found_so_far, matches->arr[k]);
char tempstr[string_length];
strcpy(tempstr, string);
char *remain = get_remaining_letters(tempstr, results->table[i][j]);
// if there are no letters remaining
if (strcmp(remain, "") == 0)
{
printf("MATCH FOUND: %s \n", found);
// alternatively, could store strings to array
}
else
{
findMatches(remain, found);
}
}
}
}
free(results->table[i][results->count[i] - 1]);
free(results->table[i]);
}
return 0;
}
How I read it (I am obviously missing something) is that it should try to match all matches, and if it can't , it should move to the next subset of letters found.
I have tries going through with a debugger, and cant make rhyme or reason of it.
As mentioned above in the commment:
get_remaining_letters used the original results->table[i][j] and removed the letters. This would leave an empty string for the next iteration and cause it to not perform as expected. Fixed by copying the string to a temporary one inside that function.
I want to replace all occurrences in an array (string) with another array.
I have a code that:
stores the string in an array in which the replacing is to take place output[],
another array that stores the string to be searched for as replace[] and a third array called toBeReplacedBy and the replacing of the first occurrence works just fine but it skips the other occurrences in the output
for example:
replace[]:
abc
toBeReplacedBy[]:
xyz
output[]:
abcdefabc
becomes
xyzdefabc
but it should become:
xyzdefxyz
I suspect the problem lies with the replacer code :
//the replacer
for (i = 0; i<80; i++) {
if (output[i] == replace[i])
output[i] = toBeReplacedBy[i];
}
//debug purpose
puts("output[]:\n");
puts(output);
return 0;
}
What have I done wrong here and how could I get it to replace all occurrences in the array.
please be aware that I only wish to use stdio.h to do this
thabks in advance
Never iterate further than the array length. This leads to undefined and possibly dangerous behaviour. If you only expect strings, use something like:
int i = 0;
while(output[i] != '\0')
{
// your logic here
i++;
}
Additionally you want to check for concurrent appearances of the same characters. But in your code you only check the first three characters. Everything after that is undefinded behaviour, because you cannot know what replace[3] returns.
Something similar to this could work:
int i = 0;
int j = 0;
int k;
while(output[i] != '\0')
{
if (output[i] == replace[j])
j++;
else
j = 0;
// replace 3 with the array length of the replace[] array
if (j == 3)
{
for(k = i; j >= 0; k-- )
{
output[k] = toBeReplacedBy[j]
j--
}
j = 0;
}
i++;
}
But please check the array boundaries.
edit: Additionally as Nellie states using a debugger would help you to understand what went wrong. Go through your program step by step and look how and when values change.
First advice is to try to debug your program if it does not work.
for (i = 0; i<80; i++) {
if (output[i] == replace[i])
output[i] = toBeReplacedBy[i];
}
There are two problems in this loop.
The first is that are iterating until i is 80. Let's look what happens when i becomes 3. output[3] in case of abcdefabc is d, but what is replace[3]? Your replacement array had only 3 letters, so you have to go back in the replacement array once you finish with one occurrence of it in the original string.
The second is that you check letter by letter.
Say you original array, which you named output somehow was abkdefabc, first three letters do not match your replacement string, but you will check the first two letters they will match with the replacement's first two letters and you will incorrectly change them.
So you need to first check that the whole replacement string is there and only then replace.
You should use strlen() to know length of your array or iterate until you reach the end of a your array ('\0').
'\0' and strlen are only available for array of char.
Your loop should looks like this :
int i = 0;
int len = strlen(my_string);
while (i < len)
{
//logic here
i = i + 1;
}
OR
int i = 0;
while (my_string[i] != '\0')
{
// logic here
i = i + 1;
}
I was doing a program to copy all string words other than its first 2 words and putting a x at the end of it.
However i cant put x at its end. Please help!!!!
Below is my code.
#include<stdio.h>
#include<string.h>
int main()
{
char a[25], b[25];
int i, j, count = 0, l, k;
scanf("%[^\n]s", a);
i = strlen(a);
if (i > 20)
printf("Given Sentence is too long.");
else
{/* checking for first 2 words and counting 2 spaces*/
for (j = 0; j < i; j++)
{
if (a[j] == ' ')
count = count + 1;
if (count == 2)
{
k = j;
break;
}
}
/* copying remaining string into new one*/
for (j = 0; j < i - k; j++)
{
b[j] = a[j + k];
}
b[j + 1] = 'x';
printf("%s", b);
}
}
you are removing first two index. But you wrote k=j and if you check the current value j there it's 1. so you are updating wrongly k because you removed 2 indexes. So k value should be 2. So checked the below code
/* copying remaining string into new one*/
for (j = 0; j < i - 2; j++)
{
b[j] = a[j + 2];
}
b[j + 1] = 'x';
printf("%s", b);
Your index is off by one. After your second loop, the condition j < i-k was false, so j now is i-k. Therefore, the character after the end of what you copied is b[j], not b[j+1]. The correct line would therefore be b[j] = 'x';.
Just changing this would leave you with something that is not a string. A string is defined as a sequence of char, ending with a '\0' char. So you have to add b[j+1] = 0; as well.
After these changes, your code does what you intended, but still has undefined behavior.
One problem is that your scanf() will happily overflow your buffer -- use a field width here: scanf("%24[^\n]", a);. And by the way, the s at the and doesn't make any sense, you use either the s conversion or the [] conversion.
A somewhat sensible implementation would use functions suited for the job, like e.g. this:
#include<stdio.h>
#include<string.h>
int main(void)
{
// memory is *cheap* nowadays, these buffers are still somewhat tiny:
char a[256];
char b[256];
// read a line
if (!fgets(a, 256, stdin)) return 1;
// and strip the newline character if present
a[strcspn(a, "\n")] = 0;
// find first space
char *space = strchr(a, ' ');
// find second space
if (space) space = strchr(space+1, ' ');
if (space)
{
// have two spaces, copy the rest
strcpy(b, space+1);
// and append 'x':
strcat(b, "x");
}
else
{
// empty string:
b[0] = 0;
}
printf("%s",b);
return 0;
}
For functions you don't know, google for man <function>.
In C strings are array of chars as you know and the way C knows it is end of the string is '\0' character. In your example you are missing at the last few lines
/* copying remaining string into new one*/
for(j=0;j<i-k;j++)
{
b[j]=a[j+k];
}
b[j+1]='x';
printf("%s",b);
after the loop ends j is already increased 1 before it quits the loop.
So if your string before x is "test", it is like
't', 'e', 's', 't','\0' in char array, and since your j is increased more than it should have, it gets to the point just right of '\0', but characters after '\0' doesnt matter, because it is the end, so your x will not be added. Simple change to
b[j]='x';
I have to search a substring in a string & display the complete word as given below everytime the substring is found-
eg:
Input: excellent
Output: excellent,excellently
I cannot figure out how to make the output like the one above.
My output:
excellent,excellently,
It always give me a comma in the end.
Prog: desc
Iteratively convert every words in the dictionary into lowercase,
and store the converted word in lower.
Use strncmp to compare the first len characters of input_str and lower.
If the return value of strncmp is 0, then the first len characters
of the two strings are the same.
void complete(char *input_str)
{
int len = strlen(input_str);
int i, j, found;
char lower[30];
found = 0;
for(i=0;i<n_words;i++)
{
for(j=0;j<strlen(dictionary[i]);j++)
{
lower[j] = tolower(dictionary[i][j]);
}
lower[j+1]='\0';
found=strncmp(input_str,lower,len);
if(found==0)//found the string n print out
{
printf("%s",dictionary[i]);
printf(",");
}
}
if (!found) {
printf("None.\n");
} else {
printf("\n");
}
}
Check if you have already printed a word before printing a second one:
char printed = 0;
for (i=0; i < n_words; i++)
{
for(j = 0; j < strlen(dictionary[i]); j++)
lower[j] = tolower(dictionary[i][j]);
lower[j + 1] = '\0';
found = strncmp(input_str, lower, len);
if (found == 0)//found the string n print out
{
if (printed)
printf(",");
printf("%s", dictionary[i]);
printed = 1;
}
}
There are two approaches that I tend to use for the comma-printing problem:
At the start of the loop, print the comma if i > 0.
At the end (after printing the real value), print the comma if i < (n - 1).
You can use either, the first is simpler since the comparison is simpler, but it can be slightly less convenient since it moves the comma-printing in time (!). On each loop iteration, you're printing the comma that belongs to the previous iteration. At least that how it's feels to me, but of course it's rather subjective.