In today's LeetCode daily challenge we were tasked to sort an string by character frequency:
Given a string s, sort it in decreasing order based on the frequency of the characters. The frequency of a character is the number of times it appears in the string.
Return the sorted string. If there are multiple answers, return any of them.
I'm a beginner and I started learning C, I did my code and it apparently it was working, however when returning the answer in the code for the site, the output I was getting was "(NULL)".
My code is as follows:
char * frequencySort(char * s){
int dictionary[56] = { 0 }; //array that stores character frequency
int length = strlen(s);
char ans[50000] = { '\0' };
//for loop that read the string and stores character frequency
for (int i = 0; i < length; i++) {
int op = s[i]-65;
dictionary[op]++;
}
//for loop that sorts the characters in order of frequency in the ans string
for (int i = 0; i < length; i++) {
int op = 0;
for (int j = 0; j < 56; j++) {
if (dictionary[j] > dictionary[op]) {
op = j;
}
}
ans[i] = op + 65;
dictionary[op]--;
while (dictionary[op] > 0) {
ans[i + 1] = op + 65;
i++;
dictionary[op]--;
}
}
return ans;
}
I tested it in VSCode and there I could use printf my ans string normally, and it would print the correct answer, like if the input was "tree", it would print "eert", but when returning the ans string to LeetCode, it returns (NULL), can anyone explain what I'm doing wrong?
Sorry for any English mistakes, it's not my first language.
Related
Different compilers are giving different outputs for the same logic in my algorithm.
I wrote the following code for a C code exercise.
The code checks for the longest string in a string vector.
But the same logic gives two different outputs.
Here's what is happening. I have no idea what I did wrong.
First version - without a printf() inside the if condition
Here the if (j > longest) just attributes new values for int longest and int index.
#include <stdio.h>
int main(void) {
char *vs[] = {"jfd", "kj", "usjkfhcs", "nbxh", "yt", "muoi", "x", "rexhd"};
int longest, index = 0;
/* i is the index for elements in *vs[].
* "jfd" is 0, "kj" is 1... */
for (int i = 0; i < sizeof(*vs); i++) {
/* j if the index for string lengths in vs[].
* for "jfd", 'j' is 0, 'f' is 1... */
for (int j = 0; vs[i][j] != '\0'; j++) {
/* if j is longer than the previous longest value */
if (j > longest) {
longest = j;
index = i;
}
}
}
printf("Longest string = %s\n", vs[index]);
return 0;
}
I ran it on https://replit.com/. It gave the unexpected output for longest string of "jfd". https://replit.com/#Pedro-Augusto33/Whatafuck-without-printf?v=1
Second version - with a printf() inside the if condition
Now I just inserted a printf() inside the if (jf > longest) condition, as seen in the code block bellow.
It changed the output of my algorithm. I have no idea how or why.
#include <stdio.h>
int main(void) {
char *vs[] = {"jfd", "kj", "usjkfhcs", "nbxh", "yt", "muoi", "x", "rexhd"};
int longest, index = 0;
/* i is the index for elements in *vs[].
* "jfd" is 0, "kj" is 1... */
for (int i = 0; i < sizeof(*vs); i++) {
/* j if the index for string lengths in vs[].
* for "jfd", 'j' is 0, 'f' is 1... */
for (int j = 0; vs[i][j] != '\0'; j++) {
/* if j is longer than the previous longest value */
if (j > longest) {
printf("Whatafuck\n");
longest = j;
index = i;
}
}
}
printf("Longest string = %s\n", vs[index]);
return 0;
}
I also ran it on https://replit.com/. It gave the expected output for longest string of "usjkfhcs". https://replit.com/#Pedro-Augusto33/Whatafuck-with-printf?v=1
Trying new compilers
After replit.com giving two different outputs, I tried another compiler to check if it also behaved strangely. https://www.onlinegdb.com/online_c_compiler gives random outputs. Sometimes it's "jfd", sometimes it's "usjkfhcs". https://onlinegdb.com/iXoCDDena
Then I went to https://www.programiz.com/c-programming/online-compiler/ . It always gives the expected output of "usjkfhcs".
So, my question is: why are different compilers behaving so strangely with my algorithm? Where is the flaw of my algorithm that makes the compilers interpret it different?
The code does not make sense.
For starters the variable longest was not initialized
int longest, index = 0;
So using it for example in this statement
if (j > longest) {
invokes undefined behavior.
In this for loop
for (int i = 0; i < sizeof(*vs); i++) {
the expression sizeof( *vs ) is equivalent to expression sizeof( char * ) and yields either 4 or 8 depending on the used system. It just occurred such a way that the array was initialized with 8 initializers. But in any case the expression sizeof( *vs ) does not provide the number of elements in an array and its value does not depend on the actual number of elements.
Using the if statement within the for loop in each iteration of the loop
for (int j = 0; vs[i][j] != '\0'; j++) {
/* if j is longer than the previous longest value */
if (j > longest) {
longest = j;
index = i;
}
}
Also does not make sense. It does not calculate the exact length of a string that is equal to j after the last iteration of the loop. So in general such a loop shall not be used for calculating length of a string.
Consider a string for example like "A". Using this for loop you will get that its length is equal to 0 while its length is equal to 1..
It seems you are trying to find the longest string a pointer to which stored in the array.
You could just use standard C string function strlen declared in header <string.h>. If to use your approach with for loops then the code can look the following way
#include <stdio.h>
int main(void)
{
const char *vs[] = { "jfd", "kj", "usjkfhcs", "nbxh", "yt", "muoi", "x", "rexhd" };
const size_t N = sizeof( vs ) / sizeof( *vs );
size_t longest = 0, index = 0;
for ( size_t i = 0; i < N; i++ )
{
size_t j = 0;
while ( vs[i][j] != '\0' ) ++j;
if ( longest < j )
{
longest = j;
index = i;
}
}
printf( "Longest string = %s\n", vs[index] );
printf( "Its length = %zu\n", longest );
return 0;
}
I'm a beginner programmer that is learning C and I'm doing some exercises on LeetCode but I ran with a problem with today's problem, I'm going to put the problem bellow but my difficult is on a do while loop that I did to loop the deleting function if there are adjacent duplicates, my code can delete the duplicates on the first iteration, but it's not looping to do any subsequent tasks, if anyone could help my I would be grateful.
The LeetCode Daily Problem (10/11/2022):
You are given a string s consisting of lowercase English letters. A duplicate removal consists of choosing two adjacent and equal letters and removing them.
We repeatedly make duplicate removals on s until we no longer can.
Return the final string after all such duplicate removals have been made. It can be proven that the answer is unique.
Example 1:
Input: s = "abbaca"
Output: "ca"
Explanation:
For example, in "abbaca" we could remove "bb" since the letters are adjacent and equal, and this is the only possible move. The result of this move is that the string is "aaca", of which only "aa" is possible, so the final string is "ca".
Example 2:
Input: s = "azxxzy"
Output: "ay"
Constraints:
1 <= s.length <= 105
s consists of lowercase English letters.
My code (testcase: "abbaca"):
char res[100]; //awnser
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;
int 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);
} while (ver > 0);
return res;
}
The fuction returns "aaca".
I did some tweaking with the code and found that after the loop the ver variable always return to 0, but I don't know why.
I see two errors
res isn't terminated so the strcpy may fail
You have two definitions of int ver so the one being incremented is not the one being checked by while (ver > 0); In other words: The do-while only executes once.
Based on your code it can be fixed like:
char res[100]; //awnser
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; // <--------------- Changed
//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++;
}
res[j] = '\0'; // <---------------- Changed
//copying the res string into the s to redo the loop if necessary
strcpy(s,res);
} while (ver > 0);
return res;
}
I have a problem, this function should return 1 if secret is composed of same letters than letters_guessed.
It works fine, as long as letters_guessed has atleast 1 same letter which are in the secret. If there is same letter 2 times or more, it does not work. I know why, but I can not solve it because I can not remove same letters.
I can not remove same letters from letters_guessed array, because it is constant, and I can not change it to nonconstant.
Again ...
If:
secret = "cat"
letters_guessed = "txaoc"
return 1
**Right**
If:
secret = "dog"
letters_guessed = "gefxd"
return 0
**Right**
If:
secret = "car"
letters_guessed = "ccr"
return 1
**Wrong, How can I solve this?**
Sorry for my bad English and long explanation.
Here is my program:
int is_word_guessed(const char secret[], const char letters_guessed[])
{
int same = 0;
for(int i = 0; i < strlen(letters_guessed); i++)
{
for(int j = 0; j < strlen(secret); j++)
{
if(letters_guessed[i] == secret[j])
same++;
}
}
if (same == strlen(secret))
return 1;
else
return 0;
}
You can:
make a copy of your strings in order to flag already counted letters (since you tell you don't want to modify the strings, I suggest making a copy first in order to discard already counted letters);
get sorted versions of your strings and then compare them with a single loop; this solution would also provide a better complexity (you could get O(n log n) instead of your current O(n^2)).
One way to do this without modifying the strings is to count the occurrences of letters in the strings. When the guess has more occurrences of a letter than the secret, it's a miss. The case where a letter occurs in the guess that isn't in the secret is just a special case, because then the count of occurrences in the secret is zero.
In practice, you don't keep two separate counts: Add the letters of the guess to the count first, then remove the letters of the secret. As soon as one count drops below zero, it's a miss.
You can make use of the fact that there are only 256 different chars and keep the counts in an array. The index to the array is the letter's ASCII code. Be careful not to access the array at negative indices. C's char isn't guaranteed to be unsigned, so you could cast it or use an unsigned temporary variable or chose not to consider negative values.
Here's an implementation:
int contains(const char *guess, const char *secret)
{
int count[256] = {0}; // start with all-zero array
while (*guess) {
unsigned char c = *guess++;
count[c]++;
}
while (*secret) {
unsigned char c = *secret++;
if (count[c] == 0) return 0;
count[c]--;
}
return 1;
}
You can keep iteration in memory by maintaining an array of all 26 alphabets.
Assumptions:- All letters should be in lower case. Secret should not have repeated letters.
Logic:- Make array entry to 1 if we have considered that letter. 97 is ascii value of 'a'
// declare header file
#include "string.h"
int is_word_guessed(const char secret[], const char letters_guessed[])
{
int same = 0;
int alphabets[26];
// make all enteries 0
for (int k = 0; k <= 25; k++)
{
alphabets[k] = 0;
}
for (int i = 0; i < strlen(letters_guessed); i++)
{
for (int j = 0; j < strlen(secret); j++)
{
if (letters_guessed[i] == secret[j] && (alphabets[(char)letters_guessed[i] - 97] == 0))
{
same++;
alphabets[(char)letters_guessed[i] - 97] = 1;
}
}
}
if (same == strlen(secret))
return 1;
else
return 0;
}
It's easy.
In Haskell it would be:
all (`elem` letters_guessed) secret
in other words: All chars in secret must be in letters_guessed.
In C its (not tested):
// Iterate though string 'secret' until there is a char not
// part of 'letters_guessed'. If there is none, return 1
unsigned check(char *secret, char *letters_guessed) {
unsigned length_secret = length(secret);
unsigned length_guessed = length(letters_guessed);
for (int i = 0; i < length_secret; i++) {
if (!elem(secret[i], letters_guessed) {
return 0;
}
}
return 1;
}
// Check if char 'current' is part of 'string'
unsigned elem(char current, char *string) {
unsigned length = length(string);
unsigned found = 0;
for (int i = 0; i < length; i++) {
if (current == string[i]) {
return 1;
}
}
return 0;
}
I wrote a function that finds the longest string in a 2d array, it works, partially. My problem is that it takes the first longest string that it finds without checking the other ones.
For example, the following list of strings:
eke
em
ekeke
eme
e
ememeememe
emem
ekekee
eooeeeeefe
eede
My function catches "ekeke" (the third string from the list) as the longest instead of "ememeememe ".
Here is my function:
void length(char str[][MAX])
{
int i = 0;
for(i = 1; i < LEN; i++)
{
if(strlen(str[i]) > strlen(str[i-1]))
{
if(strlen(str[i]) > strlen(str[i+1]))
{
printf("%s", str[i]);
break;
}
}
}
}
LEN is a constant, his value is 10.
MAX is a constant, his value is 50.
The strings are given by the user.
Thanks.
You are only comparing the previous and next strings. You need to check the lengths of all the strings.
void length(char str[][MAX])
{
size_t longest = strlen(str[0]);
szie_t j = 0;
for(size_t i = 1; i < LEN; i++)
{
size_t len = strlen(str[i]);
if(longest < len)
{
longest = len;
j = i;
}
}
printf("%s", str[j]);
}
I am assuming you have at least 1 string and handle corner cases (if user inputs less than LEN strings etc -- depends on how you fill the str with strings).
I'm trying to complete the Project Euler problem found here. For some reason my function that determines whether or not a given string is a palindrome thinks "989010" is a palindrome. The funny thing is, if I directly enter that string into the palindrome function, it functions correctly. Here's my code (I'm a newb so sorry for the bad formatting!):
bool palindrome(char pal[]);
int main(){
int i = 0;
int j = 0;
int k = 0;
int numdig = 0;
int numtest = 0;
for(i = 999; i > 99; i--){
for(j = 999;j > 99; j--){ //for loops multiply all 3 digit numbers
k = i * j;
numtest = k;
numdig = 0; //this part takes care of determining the number of digits
while(numtest > 0){
numdig++;
numtest /= 10;
}
char string[numdig + 1];
itoa (k,string,10); //itoa turns an integer into a string w/ null char.
if( palindrome(string)){
printf("It is a palindrome: %i\n",k);
system("pause");
return 0;
}
}
}
return 0;
}
bool palindrome(char pal[]){
int half = (sizeof(pal) - 1)/2; //this divides the string in half
int forward = 0;
int backward = sizeof(pal)-2;
while(forward < half && backward > 0){ //compares the charactera in the front
if(pal[forward] == pal[backward]){ //to the chars in the back until they
forward++; //meet in the middle
backward--;
}
else{
return false;
}
}
return true;
}
The sizeof of the parameter is not the character count of the string pointed to, because the parameter, despite its declaration form, is merely a pointer but not an array. Use strlen instead and notice that it does not include the terminating \0 in its returned value (as opposed to sizeof when applied to a string array).
The string "989010" looks like a palindrome if you only take the first 3 characters of it, "989". Since sizeof applied to a pointer yields 4 on your machine, it's only those first three characters that are inspected.