i have this function to print the histogram, I suppose to use this function calculate mode as well, I understand that to find mode you need to compare number of occurrences of each score, but I can't figured out how to implement this into the code. Is there anyway to implement this function to find mode?
this is my function
int calMode(RECORD list[], int count){
int tempMode = 0;
int i, k;
int current = 0;
while (current < count)
{
printf("%d:", list[current].score);
for(k=0; (i=current + k) < count ; ++k)
{
if(list[current].score == list[i].score)
printf("*");
else
break;
}
if(k > tempMode)
tempMode = k;
printf("\n");
current = current + k;
}
printf("%d\n", tempMode);
return tempMode;
}
int calMode(RECORD list[], int count){
int tempMode;
int i, k;
int current = 0;
int max = -1;
int update = 0;
while (current < count){
printf("%d:", list[current].score);
for(k=0; (i=current + k) < count ; ++k){
if(list[current].score == list[i].score)
printf("*");
else
break;
}
printf("\n");
if(k>max){
max = k;
tempMode = list[current].score;
update = 1;
} else if(k == max){
update = 0;
}
current = current + k;
}
if(update == 0)
tempMode = -1;//indeterminable
return tempMode;
}
Well, you'll need a different algorithm. You need to find the maximum .score member of your items, and store the corresponding index(es). Something like this might do:
int max = list[0].score;
RECORD *max_item[count] = { &list[0] };
size_t index = 1;
while (count-- > 1) {
// We're looking for any items that are greater than or equal to the
// current max, so when we find items that are less, we jump back to
// the condition evaluation using "continue".
if (list[count].score < max) { continue; }
// When we find a value that's greater than the current maximum, we
// need to discard all previously stored "maximum" items and update
// our current maximum.
if (list[count].score > max) {
index = 0;
max = list[count].score;
}
// At this point, the current item can't be less than the current max.
// This is because of the "continue;" earlier. Add this item to our
// list of "maximum" items.
max_item[index++] = &list[count];
}
max now stores the maximum score in your histogram, index stores the number of items that contain that maximum score and max_item stores pointers to RECORDs that contain that item.
Related
The problem is to create an array of player ranks based on 2 other arrays: leaderboard and player scores. More explanations of the problem here: https://www.hackerrank.com/challenges/climbing-the-leaderboard/problem.
The code below is a spaghetti but it's working fine. But, for large size of ranked array(200000 elements for example), it times out. I'm not asking for code to copy/paste. I just wanna know if there is a way to optimize this code.
int* climbingLeaderboard(int ranked_count, int* ranked, int player_count, int* player, int* result_count) {
*result_count=player_count;
// remove duplicates
int removed=0;
for(int i=0, j=1; i<ranked_count-removed; i++, j++){
if(ranked[i]==ranked[j]){
for(int k=j; k<ranked_count-removed; k++)
ranked[k]=ranked[k+1];
removed++;
}
}
int newsize=ranked_count-removed;
// create an array to store ranks then fill it
int* positions=malloc(newsize*sizeof(int));
positions[0]=1;
for(int i=0, j=1; j<newsize; i++, j++){
positions[j]=(ranked[j]<ranked[i])? (positions[i]+1) : positions[i];
}
// create and fill the results array using binary search
int* res = malloc(player_count*sizeof(int));
int start=0, end=newsize-1, middle=(start+end)/2;
int j, k=newsize-1;
for(int i=0; i<player_count; i++){
if(i>0&&player[i]==player[i-1]){
*(res+i)=(*(res+(i-1)));
continue;
}
if(player[i]>=ranked[middle]){
*(res+i)=positions[middle];
j=middle-1;
while(j>=0){
if(player[i]>=ranked[j])
*(res+i)=positions[j];
else if(j==k)
*(res+i)=positions[j]+1;
else break;
--j;
}
start=0; end=middle-1;
}
else{
*(res+i)=positions[newsize-1]+1;
j=newsize-1;
while(j>=middle){
if(player[i]>=ranked[j])
*(res+i)=positions[j];
else if(j==k)
*(res+i)=positions[j]+1;
else break;
--j;
}
start=middle+1; end=newsize-1;
}
middle=(start+end)/2;
}
free(positions);
return res;
}
The initial loop to remove duplicates has a potential quadratic time complexity. You can achieve linear complexity using the 2 finger approach:
int removed = 0;
for (int i = 1, j = 1; j < ranked_count; j++) {
if (ranked[i - 1] != ranked[j])
ranked[i++] = ranked[j];
else
removed++;
}
More generally, the argument arrays should not be changed in spite of the sloppy prototype given:
int *climbingLeaderboard(int ranked_count, int *ranked,
int player_count, int *player,
int *result_count);
Here are simple steps I would recommend to solve this problem:
allocate and initialize a ranking array with the ranking for each of the scores in the ranked array. Be careful to allocate ranked_count + 1 elements.
allocate a result array res of length player_count, set the result_count to player_count.
starting with pos = ranked_count, for each entry i in player:
locate the position pos where the entry would be inserted in the ranking array using binary search between position 0 and the current pos inclusive. Make sure you find the smallest entry in case of duplicate scores.
set res[i] to ranking[pos]
free the ranking array
return the res array.
Here is a simple implementation:
int *climbingLeaderboard(int ranked_count, int *ranked,
int player_count, int *player,
int *result_count)
{
if (player_count <= 0) {
*result_count = 0;
return NULL;
}
int *ranking = malloc(sizeof(*ranking) * (ranked_count + 1));
int rank = 1;
ranking[0] = rank;
for (int i = 1; i < ranked_count; i++) {
if (ranked[i] != ranked[i - 1])
rank++;
ranking[i] = rank;
}
ranking[ranked_count] = rank + 1;
int *res = malloc(sizeof(*res) * player_count);
*result_count = player_count;
int pos = ranked_count;
for (int i = 0; i < player_count; i++) {
int start = 0;
while (start < pos) {
int middle = start + (pos - start) / 2;
if (ranked[middle] > player[i])
start = middle + 1;
else
pos = middle;
}
res[i] = ranking[pos];
}
free(ranking);
return res;
}
Look for ways to use "branchless" to improve execution speed:
positions[0]=1;
for(int i=0, j=1; j<newsize; i++, j++){
positions[j]=(ranked[j]<ranked[i])? (positions[i]+1) : positions[i];
}
becomes
positions[0] = 1;
for( int i = 0, j = 1; j < newsize; i++, j++ )
positions[j] = positions[i] + (ranked[j] < ranked[i]);
Other than this, I don't even want to try to sort out what this code is attempting.
so I need to write a recursive function that gets the BST root and a another parameter that is k, and I need to find the number of nodes that are smaller or equal to k in the BST. Any Ideas?
Thanks
I tried this function but it didn't really work (worked only for the smallest 5 nodes in tree)
int avl_rank( AVLNodePtr tnode, int k )
if (tnode == NULL)
return 0;
int count = 0;
// if current root is smaller or equal
// to x increment count
if (tnode->key <= k)
count++;
// Number of children of root
int numChildren;
if (tnode->child[0]==NULL && tnode->child[0]==NULL)
numChildren = 0;
else if ((tnode->child[0]!=NULL && tnode->child[0]==NULL) || (tnode->child[0]==NULL && tnode->child[0]!=NULL))
numChildren = 1;
else numChildren = 2;
// recursively calling for every child
int i;
for ( i = 0; i < numChildren; i++)
{
AVLNodePtr child = tnode->child[i];
count += avl_rank(child, k);
}
// return the count
return count;
}
int avl_rank( AVLNodePtr tnode, int k )
{
if(tnode==NULL) return 0;
int count = 0;
if (tnode->key<=k) count++;
count += (avl_rank(tnode->child[0],k) +
avl_rank(tnode->child[1],k));
return count;
}
This code is supposed to find the smallest odd number in given array and store it in min but when I try to print min it always prints 0.
int smallestodd(int x[5]){
int j;
int k[5];
int p = 0;
int r = 0;
for(int h =0; h<5;h++){
j = x[h] % 2;
if(j == 1){
int temp =x[h];
k[p] =temp;
p++;
}
}
int min = k[0];
while(k[r] !=0){
if(k[r] < min ){
min = k[r];
r++;
}
}
return min;
}
Assuming there is an odd number in the array -- let's say trying to find the minimum odd number in an array with just even numbers (or no numbers) is UB :)
index = 0;
while (arr[index] % 2 == 0) index++; // skip even numbers
min = arr[index++]; // first odd number
while (index < length) {
if (arr[index] % 2) {
if (arr[index] < min) min = arr[index];
}
index++;
}
this code avoid overflow in search and return 1 when found or 0 if array has only even numbers.
int getMinOdd(int arr[], int length, int *value) {
int found = 0;
for(int idx=0; idx < length; idx++) {
if (arr[idx] % 2) {
if (!found || *value > arr[idx]) {
*value = arr[idx];
}
found = 1;
}
}
return found;
}
It's quite simple actually. You need to just check 2 conditions on your array.
int smallestOdd(int arr[]){
int min = 99999; //Some very large number
for(int i = 0; i < (length of your array); i++) {
if(arr[i]%2 != 0 && arr[i] < min) { //Check if number is odd and less than the current minimum value
min = arr[i];
}
}
return min;
}
Use this using statement as first :
Using System Linq;
Console.WriteLine(myArray.Where(i => i%2 == 1).Min());
I'm trying to find the most repeated int number of my vector.
Here is my code:
for (i = 0; i < dim; i++){
temp = vet[i];
for (i = 0; i < dim; i++){
if(vet[i] == temp){
count++;
}
}
if (most < count){
most = count;
elem = vet[i];
}
}
return elem;
}
It's not correct. I hope you can help me. Thank you!
The most obvious problem is that your code uses i in both the inner and the outer loops. The most and count variables are uninitialized in the above code, and count needs to be reset before starting the inner loop each time.
The method used in this code of iterating over the entire array for each element to count appearances is not very efficient. The efficiency could be improved by starting the inner loop from i + 1, instead of from 0. By doing this, the first frequency count for each element will be correct, though the later counts will be low since the earlier indices will not be visited. But this does not matter, since the first count will have set the most variable if possible. The count variable can be set to 1 before the inner loop begins, since the ith element is the test value, and the inner loop will skip this index. This change will substantially reduce the number of array accesses.
Note that this function will return the value of the first element in the array that is also the most frequently appearing.
int get_most_common(int vet[], size_t dim)
{
size_t i, j, count;
size_t most = 0;
int temp, elem;
for(i = 0; i < dim; i++) {
temp = vet[i];
count = 1;
for(j = i + 1; j < dim; j++) {
if(vet[j] == temp) {
count++;
}
}
if (most < count) {
most = count;
elem = vet[i];
}
}
return elem;
}
You can always try the brute force method, count the frequency of each element, then find the maximum one.
To implement a full version of such function with efficiency, you will need special data structure such as hashtable or dictionary.
But the following codes work well if you just need to return the first item that match such condition.
#include <stdio.h>
// returns the first matched most frequent item of a list
// list items of same value must be grouped, for example, a sorted list
// only returns the first matched item
int max_frequent_item_of(int vet[], int dim)
{
int i = 0;
// element and its count of current sublist
int current = vet[0];
int current_count = 0;
// most frequent element and its count of the list so far
int most = vet[0];
int most_count = 0;
while (i < dim) {
// if i-th element still belong to current sublist, run the counter
if (vet[i] == current) {
current_count += 1;
i += 1;
}
// otherwise, the current sublist just ended
else {
// update the most frequent element
if (current_count > most_count) {
most = current;
most_count = current_count;
}
// reset current sublist
current = vet[i];
current_count = 1;
i += 1;
}
}
printf("most frequent item %d, count %d\n", most, most_count);
return most;
}
int main(void)
{
// vet must be in order, sort with `qsort` if necessary
int vet[] = {1, 1, 2, 3, 4, 4, 4, 8, 9, 9};
int size = 10;
int n;
printf("list: ");
for (n = 0 ; n < size; n++)
{
printf("%d ", vet[n]);
}
printf("\n");
max_frequent_item_of(vet, size);
return 0;
}
output
list: 1 1 2 3 4 4 4 8 9 9
most frequent item 4, count 3
I write This Code do what you need and extra if two numbers have the same repeating times, it returns the Bigger one.
int ReturnMostRepeated(int val[], size_t dim)
{
size_t i,j,count;
int temp=0, temp2;
for(i =0;i<dim;i++)
{
count = 1;
for(j=i+1;j<dim;j++)
{
if(val[j]==val[i])
{
count++;
}
}
if (count>temp)
{
temp = count;
temp2 = val[i];
}else if(count == temp) if (val[i]>temp2) temp2 = val[i];
}
return temp2;
}
I posted earlier about a runtime error in my C program but now I'm having another issue with the code. My program runs fine without any errors but it always prints 0 no matter what the input. I've spent the last 4 hours trying to figure out why my code is doing that but I've had no luck. I would really appreciate if someone could give me a hand.
My program takes in an input of a sequence of integers, using another program that works like scanf. Getint() reads an input of a sequence of integers and stops reading the input when it reaches EOF (-1). The number of integers in the sequence is 1000.
// ar_max(a[]) returns the max entry of a
int ar_max(int a[]) {
int max_so_far = a[0];
for (int i = 1; i < 1000; i++) {
if (a[i] > max_so_far) {
max_so_far = a[i];
}
}
return max_so_far;
}
int main() {
int inputnum = getint();
// array containing the distinct numbers seen
int a_num[1000] = {};
// array containing the frequencies of the distinct numbers seen
int a_freq[1000] = {};
int len_n = 0;
while (inputnum != EOF) {
int i = 0;
len_n = i + 1;
int len_f = len_n;
// update the frequency of inputnum if it's already been seen
for (i = 0; i < len_f; i++, len_n += 1) {
if (a_num[i] == inputnum) {
a_freq[i] = a_freq[i] + 1;
}
}
// add inputnum into the array if it hasn't already been seen
if (i == len_n) {
a_num[i+1] = inputnum;
a_freq[i+1] = 1;
}
inputnum = getint();
}
// print the first number with the highest frequency
for (int j = 0; j < len_n; j++) {
if (a_freq[j] == ar_max(a_freq)) {
printf("%d\n", a_num[j]);
break;
}
}
}
For example, an input of
10 20 30 20
should result in 20
The code has the right idea, but it still has some problems.
First, you have two arrays with related information. You keep two lengths for each of these arrays and try to keep the lengths the same. That's complicated. Instead, consider having just one length for both arrays.
When you loop thorugh the array in oder to check whether the given number is already contained in the array:
for (i = 0; i < len_f; i++, len_n += 1) {
if (a_num[i] == inputnum) {
a_freq[i] = a_freq[i] + 1;
}
}
you update then length of the number array with each iteration. You shouldn't, because you are not changing the length of anything while iterating though the loop.
Next, you check whether the number hasn't been found with:
if (i == len_n) ...
That doesn't work, because you update the frequency in the first loop, but don't terminate the loop; your condition will always be true. You can fix this by breaking out of the loop explicitly with break when you have found the number. (Better yet, make the look-up and frequency update a function whose return value indicates whether the element was found and add the elemen if it wasn't.)
When you append the new element:
if (i == len_n) {
a_num[i+1] = inputnum;
a_freq[i+1] = 1;
}
you should, of course, increment the length of the array you append to. In general, appending an item to an array looks like this:
array[len++] = item;
Recall that the first index is zero and that the actual length is one beyond the valid indices.
There are other points:
When you add an element, you should make sure that you don't overflow the array. The dimension of 1000 is generous, but not infinite.
In your function ar_max, you iterate over all 1000 elements of the array. You have initialised the arrays to zero, so the maximum will still be right, but it is better to pass the array size to the function, too, so that you can iterate over only the actual items.
If your function ar_max returned an index instead of a value, you could access both array with that index and you wouldn't need the last loop over j, because j is just that index.
If you have two parallel arrays, it is a good idea to create a struct that hold the item and frequency and always keeps them together. That simplifies the code, because you don't have to keep anything in sync. Such a data layout also lends itself to sorting and filtering other common operations.
Here's a version that implements the fixes described above. It also uses a function to look up an element by value and makes ar_max return an array index instead of a value.
#include <stdlib.h>
#include <stdio.h>
#define MAX 1000
int getint()
{
int x;
if (scanf("%d", &x) < 1) return EOF;
return x;
}
int ar_max(const int a[], int len)
{
if (len == 0) return -1;
int max_so_far = a[0];
int max_index = 0;
for (int i = 1; i < len; i++) {
if (a[i] > max_so_far) {
max_so_far = a[i];
max_index = i;
}
}
return max_index;
}
int ar_find(const int a[], int len, int which)
{
for (int i = 0; i < len; i++) {
if (a[i] == which) return i;
}
return -1;
}
int main()
{
int inputnum = getint();
int a_num[MAX] = { }; // distinct numbers seen
int a_freq[MAX] = { }; // frequencies of the distinct numbers
int len = 0; // actual length of both arrays
while (inputnum != EOF) {
int i = ar_find(a_num, len, inputnum);
if (i < 0) { // append new item
if (len >= MAX) {
fprintf(stderr, "Array size %d exceeded\n", MAX);
exit(1);
}
a_num[len] = inputnum;
a_freq[len] = 1;
len++;
} else { // increment existing item
a_freq[i]++;
}
inputnum = getint();
}
int imax = ar_max(a_freq, len);
if (imax >= 0) {
printf("%d (%d times)\n", a_num[imax], a_freq[imax]);
} else {
puts("Empty input.");
}
return 0;
}
int main()
{
// array containing the distinct numbers seen
int a_num[1000] = {0};
// array containing the frequencies of the distinct numbers seen
int a_freq[1000] = {0};
int len_n = 0;
int i = 0, j = 0;
// Read first entry
int inputnum = getint();
if (EOF == inputnum)
{
printf("No valid number input given\n");
return -1;
}
// Make first entry in a_num and a_freq
a_num[0] = inputnum;
a_freq[0] = 1;
// Update len_n to 1
len_n = 1;
// Get new entry from user and update number array and frequency array
inputnum = getint();
while (inputnum != EOF)
{
// update the frequency of inputnum if it's already been seen
for (i = 0; i < len_n; i++)
{
if (a_num[i] == inputnum)
{
a_freq[i] = a_freq[i] + 1;
break;
}
}
// add inputnum into the array if it hasn't already been seen
if (i == len_n)
{
a_num[i] = inputnum;
a_freq[i] = 1;
// Update len_n
len_n++;
}
// Check if we have already reached 1000
if (1000 == len_n)
{
printf("Reached 1000 entry read\n");
break;
}
// Next entry
inputnum = getint();
}
// print the number with the highest frequency
int max_freq = ar_max(a_freq);
for (j = 0; j < len_n; j++)
{
if (a_freq[j] == max_freq)
{
printf("%d\n", a_num[j]);
break;
}
}
}
NOTE:
1. #define MAX_SIZE 1000 can be used since hardcoded value 1000 is used repeatedly in code. This will help when you have use new size (say 1500) and you need to change only the #define MAX_SIZE 1500, other code remains unchanged.
2. ar_max() function can be modified to give array index where max occurs to avoid the for loop in main to find the array index. e.g.
int ar_max(int a[])
{
int index = 0;
int max_so_far = a[0];
for (int i = 1; i < 1000; i++) {
if (a[i] > max_so_far) {
max_so_far = a[i];
index = i;
}
}
return index;
}
In main():
printf("%d\n", a_num[ar_max(a_freq)]);