Why did I get Wrong Answer on this problem(Uva OJ 455) - c

I'm crazy about this problem (Uva 455):
A character string is said to have period k if it can be formed by
concatenating one or more repetitions of another string of length k.
For example, the string ”abcabcabcabc” has period 3, since it is
formed by 4 repetitions of the string ”abc”. It also has periods 6
(two repetitions of ”abcabc”) and 12 (one repetition of
”abcabcabcabc”).
Write a program to read a character string and
determine its smallest period.
Input
The first line oif the input file
will contain a single integer N indicating how many test case that
your program will test followed by a blank line. Each test case will
contain a single character string of up to 80 non-blank characters.
Two consecutive input will separated by a blank line.
Output
An
integer denoting the smallest period of the input string for each
input. Two consecutive output are separated by a blank line.
Sample Input
1
HoHoHo
Sample Output
2
I've checked all test cases I could imagine and all of them returned correct result, but I still get Wrong Answer on the online judge. Where did I go wrong?
(English is not my native language; please excuse typing or syntax errors.)
#include <stdio.h>
#include <string.h>
#define maxn 85
int check(char* s, int per){
for(int i = 0; i < strlen(s) - per; i++){
if(s[i + per] != s[i]) return 0;
}
return 1;
}
int main(){
int T;
scanf("%d", &T);
char s[maxn];
while(T--){
scanf("%s", s);
int len = strlen(s);
bool OK = false;
for(int i = 1; i <= len/2 && (len % i == 0); i++){//That's wrong.
if(check(s, i)){
printf("%d\n", i);
OK = true;
break;
}
}
if(!OK) printf("%d\n", len);
if(T) printf("\n");
}
return 0;
}

The problem is in for(int i = 1; i <= len/2 && (len % i == 0); i++). You are stopping as soon as you encounter an i that doesn't divide len, instead of skipping it.
Write the loop as:
for (int i = 1; i <= len/2; i++) {
if (len % i != 0) continue;
...
}

Related

Digit Frequency calculating code in C not working

So, I was writing this code for counting the digit frequency i.e. the number of times the digits from 0-9 has appeared in a user inputted string(alphanumeric). So, I took the string, converted into integer and tried to store the frequency in "count" and print it but when I run the code, count is never getting incremented and the output comes all 0s. Would be grateful if anyone points out in which part my logic went wrong.
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
int main() {
// takes string input
char *s;
s = malloc(1024 * sizeof(char));
scanf("%[^\n]", s);
s = realloc(s, strlen(s) + 1);
//turns the string to int
int x = atoi(s);
int temp = x, len = 0;
//calculates string length
while (x != 0) {
x = x / 10;
len++;
}
x = temp;
//parses through the string and matches digits with each number
for (int j = 0; j < 10; j++){
int count = 0;
for(int i = 0; i < len; i++){
if(x % 10 == j){
count++;
}
x = x / 10;
}
x = temp;
printf("%d ", count);
}
return 0;
}
To write a correct and reasonable digit-counting program:
Do not allocate any buffer for this.
Create an array to count the number of times each digit occurs. The array should have ten elements, one for each digit.
Initialize the array to zero in each element.
In a loop, read one character at a time.
Leave the loop when the read routine (such as getchar) indicates end-of-file or a problem, or, if desired, returns a new-line or other character you wish to use as an end-of-input indication.
Inside the loop, check whether the character read is a digit. If the character read is a digit, increment the corresponding element of the array.
After the loop, execute a new loop to iterate through the digits.
Inside that loop, for each digit, print the count from the array element for that digit.
Your approach is way to complicated for a very easy task. This will do:
void numberOfDigits(const char *s, int hist[10]) {
while(*s) {
if(isdigit(*s))
hist[*s - '0']++;
s++;
}
}
It can be used like this:
int main(void) {
char buf[1024];
int hist[10];
fgets(buf, sizeof buf, stdin);
numberOfDigits(s, hist);
for(int i=0; i<10; i++)
printf("Digit %d occurs %d times\n", i, hist[i]);
}
This can also be quite easily achieved without a buffer if desired:
int ch;
int hist[10];
while((ch = getchar()) != EOF) {
if(isdigit(ch))
hist[ch - '0']++;
}
#include <stdio.h>
int main(void) {
int input = 1223330;
int freq[10] = {0};
input = abs(input);
while(input)
{
freq[input%10]++;
input /= 10;
}
for(int i=0; i<10; ++i)
{
printf("%d: %.*s\n", i, freq[i], "*************************************************");
}
return 0;
}
Output:
Success #stdin #stdout 0s 5668KB
0: *
1: *
2: **
3: ***
4:
5:
6:
7:
8:
9:
This app is currently limited by the size of an int (approximately 9 or 10 digits).
You can update it to use a long long easily, which will get you to about 19 digits.

Manipulating dynamically allocated 2D char arrays in C

I'm having trouble with trying to manipulate 2d dynamic arrays in C. What I want to do is to store a char string in every row of the the 2d array then perform a check to see if the string contains a certain character, if so remove all occurrences then shift over the empty positions. What's actually happening is I get an exit status 1.
More about the problem, for example if I have
Enter string 1: testing
Enter string 2: apple
Enter string 3: banana
I would want the output to become
What letter? a // ask what character to search for and remove all occurences
testing
pple
bnn
Here is my full code:
#include <stdio.h>
#include <stdlib.h>
void removeOccurences2(char** letters, int strs, int size, char letter){
// Get size of array
// Shift amount says how many of the letter that we have removed so far.
int shiftAmt = 0;
// Shift array says how much we should shift each element at the end
int shiftArray[strs][size];
// The first loop to remove letters and put things the shift amount in the array
int i,j;
for(i=0;i < strs; i++){
for(j = 0; j < size - 1; j++) {
if (letters[i][j] == '\0'){
break;
}
else {
// If the letter matches
if(letter == letters[i][j]){
// Set to null terminator
letters[i][j] = '\0';
// Increase Shift amount
shiftAmt++;
// Set shift amount for this position to be 0
shiftArray[i][j] = 0;
}else{
// Set the shift amount for this letter to be equal to the current shift amount
shiftArray[i][j] = shiftAmt;
}
}
}
}
// Loop back through and shift each index the required amount
for(i = 0; i < strs; i++){
for(j = 0; j < size - 1; j++) {
// If the shift amount for this index is 0 don't do anything
if(shiftArray[i][j] == 0) continue;
// Otherwise swap
letters[i][j - shiftArray[i][j]] = letters[i][j];
letters[i][j] = '\0';
}
//now print the new string
printf("%s", letters[i]);
}
return;
}
int main() {
int strs;
char** array2;
int size;
int cnt;
int c;
char letter;
printf("How many strings do you want to enter?\n");
scanf("%d", &strs);
printf("What is the max size of the strings?\n");
scanf("%d", &size);
array2 = malloc(sizeof(char*)*strs);
cnt = 0;
while (cnt < strs) {
c = 0;
printf("Enter string %d:\n", cnt + 1);
array2[cnt] = malloc(sizeof(char)*size);
scanf("%s", array2[cnt]);
cnt += 1;
}
printf("What letter?\n");
scanf(" %c", &letter);
removeOccurences2(array2,strs,size,letter);
}
Thanks in advance!
You can remove letters from a string in place, because you can only shorten the string.
The code could simply be:
void removeOccurences2(char** letters, int strs, int size, char letter){
int i,j,k;
// loop over the array of strings
for(i=0;i < strs; i++){
// loop per string
for(j = 0, k=0; j < size; j++) {
// stop on the first null character
if (letters[i][j] == '\0'){
letters[i][k] = 0;
break;
}
// If the letter does not match, keep the letter
if(letter != letters[i][j]){
letters[i][k++] = letters[i][j];
}
}
//now print the new string
printf("%s\n", letters[i]);
}
return;
}
But you should free all the allocated arrays before returning to environment, and explicitely return 0 at the end of main.
Well, there are several issues on your program, basically you are getting segmentation fault error because you are accessing invalid memory which isn't allocated by your program. Here are some issues I found:
shiftAmt isn't reset after processing/checking each string which lead to incorrect value of shiftArray.
Values of shiftArray only set as expected for length of string but after that (values from from length of each string to size) are random numbers.
The logic to delete occurrence character is incorrect - you need to shift the whole string after the occurrence character to the left not just manipulating a single character like what you are doing.
1 & 2 cause the segmentation fault error (crash the program) because it causes this line letters[i][j - shiftArray[i][j]] = letters[i][j]; access to unexpected memory. You can take a look at my edited version of your removeOccurences2 method for reference:
int removeOccurences2(char* string, char letter) {
if(!string) return -1;
int i = 0;
while (*(string+i) != '\0') {
if (*(string+i) == letter) {
memmove(string + i, string + i + 1, strlen(string + i + 1));
string[strlen(string) - 1] = '\0'; // delete last character
}
i++;
}
return 0;
}
It's just an example and there is still some flaw in its logics waiting for you to complete. Hint: try the case: "bananaaaa123"
Happy coding!
"...if the string contains a certain character, if so remove all occurrences then shift over the empty positions."
The original string can be edited in place by incrementing two pointers initially containing the same content. The following illustrates.:
void remove_all_chars(char* str, char c)
{
char *pr = str://pointer read
char *pw = str;//pointer write
while(*pr)
{
*pw = *pr++;
pw += (*pw != c);//increment pw only if current position == c
}
*pw = '\0';//terminate to mark last position of modified string
}
This is the cleanest, simplest form I have seen for doing this task. Credit goes to this answer.

Program runs too slowly with large input - C

The goal for this program is for it to count the number of instances that two consecutive letters are identical and print this number for every test case. The input can be up to 1,000,000 characters long (thus the size of the char array to hold the input). The website which has the coding challenge on it, however, states that the program times out at a 2s run-time. My question is, how can this program be optimized to process the data faster? Does the issue stem from the large char array?
Also: I get a compiler warning "assignment makes integer from pointer without a cast" for the line str[1000000] = "" What does this mean and how should it be handled instead?
Input:
number of test cases
strings of capital A's and B's
Output:
Number of duplicate letters next to each other for each test case, each on a new line.
Code:
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
int main() {
int n, c, a, results[10] = {};
char str[1000000];
scanf("%d", &n);
for (c = 0; c < n; c++) {
str[1000000] = "";
scanf("%s", str);
for (a = 0; a < (strlen(str)-1); a++) {
if (str[a] == str[a+1]) { results[c] += 1; }
}
}
for (c = 0; c < n; c++) {
printf("%d\n", results[c]);
}
return 0;
}
You don't need the line
str[1000000] = "";
scanf() adds a null terminator when it parses the input and writes it to str. This line is also writing beyond the end of the array, since the last element of the array is str[999999].
The reason you're getting the warning is because the type of str[10000000] is char, but the type of a string literal is char*.
To speed up the program, take the call to strlen() out of the loop.
size_t len = strlen(str)-1;
for (a = 0; a < len; a++) {
...
}
str[1000000] = "";
This does not do what you think it does and you're overflowing the buffer which results in undefined behaviour. An indexer's range is from 0 - sizeof(str) EXCLUSIVE. So you either add one to the
1000000 when initializing or use 999999 to access it instead. To get rid of the compiler warning and produce cleaner code use:
str[1000000] = '\0';
Or
str[999999] = '\0';
Depending on what you did to fix it.
As to optimizing, you should look at the assembly and go from there.
count the number of instances that two consecutive letters are identical and print this number for every test case
For efficiency, code needs a new approach as suggeted by #john bollinger & #molbdnilo
void ReportPairs(const char *str, size_t n) {
int previous = EOF;
unsigned long repeat = 0;
for (size_t i=0; i<n; i++) {
int ch = (unsigned char) str[i];
if (isalpha(ch) && ch == previous) {
repeat++;
}
previous = ch;
}
printf("Pair count %lu\n", repeat);
}
char *testcase1 = "test1122a33";
ReportPairs(testcase1, strlen(testcase1));
or directly from input and "each test case, each on a new line."
int ReportPairs2(FILE *inf) {
int previous = EOF;
unsigned long repeat = 0;
int ch;
for ((ch = fgetc(inf)) != '\n') {
if (ch == EOF) return ch;
if (isalpha(ch) && ch == previous) {
repeat++;
}
previous = ch;
}
printf("Pair count %lu\n", repeat);
return ch;
}
while (ReportPairs2(stdin) != EOF);
Unclear how OP wants to count "AAAA" as 2 or 3. This code counts it as 3.
One way to dramatically improve the run-time for your code is to limit the number of times you read from stdin. (basically process input in bigger chunks). You can do this a number of way, but probably one of the most efficient would be with fread. Even reading in 8-byte chunks can provide a big improvement over reading a character at a time. One example of such an implementation considering capital letters [A-Z] only would be:
#include <stdio.h>
#define RSIZE 8
int main (void) {
char qword[RSIZE] = {0};
char last = 0;
size_t i = 0;
size_t nchr = 0;
size_t dcount = 0;
/* read up to 8-bytes at a time */
while ((nchr = fread (qword, sizeof *qword, RSIZE, stdin)))
{ /* compare each byte to byte before */
for (i = 1; i < nchr && qword[i] && qword[i] != '\n'; i++)
{ /* if not [A-Z] continue, else compare */
if (qword[i-1] < 'A' || qword[i-1] > 'Z') continue;
if (i == 1 && last == qword[i-1]) dcount++;
if (qword[i-1] == qword[i]) dcount++;
}
last = qword[i-1]; /* save last for comparison w/next */
}
printf ("\n sequential duplicated characters [A-Z] : %zu\n\n",
dcount);
return 0;
}
Output/Time with 868789 chars
$ time ./bin/find_dup_digits <dat/d434839c-d-input-d4340a6.txt
sequential duplicated characters [A-Z] : 434893
real 0m0.024s
user 0m0.017s
sys 0m0.005s
Note: the string was actually a string of '0's and '1's run with a modified test of if (qword[i-1] < '0' || qword[i-1] > '9') continue; rather than the test for [A-Z]...continue, but your results with 'A's and 'B's should be virtually identical. 1000000 would still be significantly under .1 seconds. You can play with the RSIZE value to see if there is any benefit to reading a larger (suggested 'power of 2') size of characters. (note: this counts AAAA as 3) Hope this helps.

Understanding the strcmp() function in One month reminder progam

Here is the program that prints a one month reminder list. This is an example from K.N. King book. My problem is that I can't understand about how strcmp function works in this program.
#include <stdio.h>
#include <string.h>
#define MAX_REMIND 50 /* Maximum number of reminders */
#define MSG_LEN 60 /* max length of reminders message */
int read_line(char str[], int n);
int main(void) {
char reminders[MAX_REMIND][MSG_LEN+3];
char day_str[3], msg_str[MSG_LEN+1];
int day, i, j, num_remind = 0;
for(;;) {
if(num_remind == MAX_REMIND) {
printf("--No space left--\n");
break;
}
printf("Enter day and reminder: ");
scanf("%2d", &day);
if(day == 0)
break;
sprintf(day_str, "%2d", day);
read_line(msg_str, MSG_LEN);
for(i = 0; i < num_remind; i++)
if(strcmp(day_str, reminders[i]) < 0)
break;
for(j = num_remind; j > i; j--)
strcpy(reminders[j], reminders[j - 1]);
strcpy(reminders[i], day_str);
strcat(reminders[i], msg_str);
num_remind++;
}
printf("\nDay Reminder\n");
for(i = 0; i < num_remind; i++)
printf(" %s\n", reminders[i]);
return 0;
}
int read_line(char str[], int n) {
int ch, i = 0;
while((ch = getchar()) != '\n')
if (i < n)
str[i++] = ch;
str[i] = '\0';
return i;
}
What I understood is that, strings are stored in 2D array in which every row accepts string from the user. The program first takes date (in two decimal from the user) and convert it into string using sprintf() function. Then it compares the converted string date with the string stored in reminder[][] array.
I can't understand how it compares date with string. (It always return true in that case and breaks for statement at i = 0 everytime).
strcmp used in this code is used for sorting. Add some debug code (after line 27) and you will see what result is produced by strcmp:
for(i = 0; i < num_remind; i++) {
printf("%s comparing to %s is %d \n", day_str, reminders[i], strcmp(day_str, reminders[i]));
if(strcmp(day_str, reminders[i]) < 0) {
break;
}
}
As you can see the for loop is interrupted when the new entered day_str is smaller than any other reminder from the beginning of the stored reminders.
Obtained i in this way is used in the next for loop to shift all stored reminders from num_remind to i each by 1 place (from last element to i).
At last these two lines are placing day_str and msg_str in the right place:
strcpy(reminders[i], day_str);
strcat(reminders[i], msg_str);
Take a look at this Insertion sort to understand this kind of sorting.
The 'day' variable is an integer, which is composed into a string with the format "%2d", so the number 6 becomes " 6".
Then the program loops through the reminders, and breaks on this condition:
if(strcmp(day_str, reminders[i]) < 0)
strcmp is being used here to determine whether the string in day_str sorts earlier than the string in reminders[i].
The reminders[] array is therefore sorted by ascending days. This loop breaks at the insertion point for the new data. Then it moves all the existing reminders down one position in the array, making room to insert the new data.

C Program not running as intended, hangs after input

The program I am writing to take a number and display that number as a calculator would display it (shown below) is compiling with no issues, but when I try to run it, I am able to input my number, but nothing happens. It seems like it is "hanging", since no further output is shown as I would have expected. Might anyone know what the problem is?
#include <stdio.h>
#define MAX_DIGITS 20
char segments[10][7] = /* seven segment array */
{{'1','1','1','1','1','1','0'}, /* zero */
{'0','1','1','0','0','0','0'}, /* one */
{'1','1','0','1','1','0','1'}, /* two */
{'1','1','1','1','0','0','1'}, /* three */
{'0','1','1','0','0','1','1'}, /* four */
{'1','0','1','1','0','1','1'}, /* five */
{'1','0','1','1','1','1','1'}, /* six */
{'1','1','1','0','0','0','0'}, /* seven */
{'1','1','1','1','1','1','1'}, /* eight */
{'1','1','1','0','0','1','1'}};/* nine */
char digits[3][MAX_DIGITS * 4]; /* digits array */
int i, j; /* count variables */
int adjust; /* output formatting */
int main(void) {
clear_digits_array();
int digit[20];
for (i = 0; i < 20; i++) {
digit[i] = 0;
}
int count = 20;
int position = 0;
printf("Enter a number: ");
int number = scanf("%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d",
&digit[0],
&digit[1],
&digit[2],
&digit[3],
&digit[4],
&digit[5],
&digit[6],
&digit[7],
&digit[8],
&digit[9],
&digit[10],
&digit[11],
&digit[12],
&digit[13],
&digit[14],
&digit[15],
&digit[16],
&digit[17],
&digit[18],
&digit[19]); //NOTHING HAPPENS AFTER HERE
printf("Got input, number is %d", number);
while (count > 0) {
printf("Reading digits, count is %d", count);
process_digit(digit[20 - count], position);
position++;
count--;
}
print_digits_array();
printf("\n");
return 0;
}
void clear_digits_array(void) {
/* fill all positions in digits array with blank spaces */
for (i = 0; i < 3; i++) {
for (j = 0; j < (MAX_DIGITS * 4); j++) {
digits[i][j] = ' ';
}
}
}
void process_digit(int digit, int position) {
/* check each segment to see if segment should be filled in for given digit */
for (i = 0; i < 7; i++) {
printf("Processing digit %d at position %d, i is %d", digit, position, i);
if (segments[digit][i] == 1) {
switch (i) {
case 0: digits[0][(position * 4) + 1] = '_';
break;
case 1: digits[1][(position * 4) + 2] = '|';
break;
case 2: digits[2][(position * 4) + 2] = '|';
break;
case 3: digits[2][(position * 4) + 1] = '_';
break;
case 4: digits[2][(position * 4) + 0] = '|';
break;
case 5: digits[1][(position * 4) + 0] = '|';
break;
case 6: digits[1][(position * 4) + 1] = '_';
break;
}
}
}
}
void print_digits_array(void) {
/* print each character in digits array */
for (i = 0; i < 3; i++) {
for (j = 0; j < (MAX_DIGITS * 4); j++) {
printf("%c", digits[i][j]);
}
printf("/n");
}
}
Your code includes:
printf("Enter a number: ");
int number = scanf("%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d",
&digit[0],
&digit[1],
&digit[2],
&digit[3],
&digit[4],
&digit[5],
&digit[6],
&digit[7],
&digit[8],
&digit[9],
&digit[10],
&digit[11],
&digit[12],
&digit[13],
&digit[14],
&digit[15],
&digit[16],
&digit[17],
&digit[18],
&digit[19]); //NOTHING HAPPENS AFTER HERE
Have you entered twenty separate digits? If not, scanf() is waiting for you to type some more numbers.
Note that the return value from scanf() is the number of successfully converted numbers (0..20 in the example), not the value you entered.
Is that the issue? I tried to make it such that the maximum amount of numbers the user could enter was 20, and if any more were entered they would be ignored, or if fewer were entered, it would only consider those (say, 5 were entered, then only the 5 would be used). Is there an easier way to do this sort of thing then?
Yes, I think that's the issue.
There are probably several easier ways to do it. I'd be tempted to use:
char buffer[22]; // 20 digits, newline, null
if (fgets(buffer, sizeof(buffer), stdin) != EOF)
{
size_t len = strlen(buffer);
if (len >= sizeof(buffer) - 1)
{
fprintf(stderr, "You entered too long a string (maximum 20 digits)\n");
exit(EXIT_FAILURE);
}
if (len > 0)
buffer[--len] = '\0'; // Zap newline — carefully
for (int i = 0; i < len; i++)
{
if (!isdigit(buffer[i]))
{
fprintf(stderr, "Non-digit %c found\n", buffer[i]);
exit(EXIT_FAILURE);
}
}
...and from here, process the digits in buffer, one at a time...
...Use buffer[i] - '0' to get a number 0..9 from the character in buffer...
}
Another option is to use a long long number, but that only gives you up to 18 digits (signed) or 19 digits (unsigned), with some values of 19 or 20 also within range. You'd then strip the digits out of the number using division and modulus operations.
long long value;
if (scanf("%lld", &value) == 1)
{
if (value < 0)
...error processing...
do
{
int digit = value % 10;
value /= 10;
...process digit...
} while (value > 0);
}
This has some merits, but in practice, I'd be tempted to use fgets() to read a line of input, and either sscanf() or strtoll() to convert and validate the number. That isn't as simple as it looks; the error returns from strtoll(), in particular, are many and subtle, and none of the scanf() family handle overflowing numbers gracefully. You could constrain the scanf() though with %18lld so that no more than 18 digits are read, but that would mean that if the user typed 19 or more digits, you'd get the leftovers on the next attempt to read with scanf(). So, handling scanf() is not simple either, especially if you need to convert multiple numbers in a single run of the program.
With those caveats out of the way, you can usually do a 'good enough' job with a sensible person providing the input. It is the process of making a program bomb-proof (foolproof — as in, proof against fools) that is hard. I find meaningful error reporting easier when I can report the whole string that was read in (as with fgets()); with scanf(), you can't see the characters that were entered and consumed before something went wrong.
use GDB, here is introduction for it http://www.gnu.org/software/gdb/
look into this tutorial too http://www.cs.cmu.edu/~gilpin/tutorial/
int number = scanf("%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d",
&digit[0],
&digit[1],
&digit[2],
&digit[3],
&digit[4],
&digit[5],
&digit[6],
&digit[7],
&digit[8],
&digit[9],
&digit[10],
&digit[11],
&digit[12],
&digit[13],
&digit[14],
&digit[15],
&digit[16],
&digit[17],
&digit[18],
&digit[19]);
I don't think this is a good idea use loop here
for (i = 0; i < 20; i++)
scanf("%d",&digit[i]);
And if you need the number
then do like this
int number = i; when loop finishes.
You can also try this
char buf[12];
while((c=getchar())!=EOF && i < 20)
{
buf[j++] =c;
if((c == '\n' || c == ' ' || c == '\t') && (sscanf(buf,"%d",&digit[i])) == 1)
{
i++;
j = 0;
}
}
For EOF you will have to press CTRL+D
In this way you can take 20 or less integers

Resources