find the n largest elements in an array - c

I have an array and I need to find n tie cases in the array for example {1,2,3,3} I need the program to return both 3's
void print_winner(void)
{
// TODO
string arr[9];
string name = "";
int largest = 0;
for (int i = 0; i < voter_count; i++)
{
if (largest<candidates[i].votes)
{
largest = candidates[i].votes;
name = candidates[i].name;
}
}
// arr[0] = name;
printf("%s\n", name);
return;
}
in this code candidates is a struct with two attributes: name and votes
I need the program to print the name with the highest number of votes even if there is a 3-way tie
I was thinking I would traverse the list find the largest int and then remove that int and traverse the list again to see if any elements equal the largest element from the original list and if so add the name to the array and in the end print all the name(s)

An approach in programming that is often good is to divide the problem up and solve its separate parts.
In this case, one way of setting up the problem is to print the names of all those that have the highest score. But that problem is somewhat complex.
An alternative way of setting up the problem would be as follow:
Find the maximum score.
After having found the maximum score, print the names of all those that have the highest score.
Each of these sub-problems are easier, and should together solve the problem.
I much prefer teaching others how to fish, so I don't want to spoil or ruin your chances for learning and improving and becoming awesome by implementing the solution for you in code. You are more than welcome to ask for clarification, however, I very much like to help :).

I think u just need to loop the array again after you find the candidate with max votes, to look for if there is another candidate or more with same no. of votes.No need to remove records.

Until you passed every vote count, you do not know the largest vote count.
The currently largest's name would be needed to be corrected when a really larger largest is found. So do:
void print_winner_1(void)
{
// globals: candidates: array
// voter_count: size of array
int largest = 0;
for (int i = 0; i < voter_count; i++)
{
if (largest < candidates[i].votes)
{
largest = candidates[i].votes;
}
}
for (int i = 0; i < voter_count; i++)
{
if (largest == candidates[i].votes)
{
printf("%s\n", candidates[i].name);
}
}
}
The above could store a largest_first_i for a small speed improvement.
Collecting intermediary results in full:
void print_winner_2(void)
{
// globals: candidates: array
// voter_count: size of array
string names[9]; // Tie names.
int name_count = 0;
int largest = 0;
for (int i = 0; i < voter_count; i++)
{
if (largest < candidates[i].votes)
{
name_count = 0; // Reset list of ties.
largest = candidates[i].votes;
}
if (largest == candidates[i].votes)
{
if (name_count == 9) { // More than 9 temporary (!) ties.
print_winner_1();
return;
}
names[name_count++] = candidates[i].name;
}
}
for (int i = 0; i < name_count; i++)
{
printf("%s\n", names[i]);
}
}
I did one with two full loops, and one collecting the ties immediately.
The second solution is prone to overflow of the result array (if there are more than 9 candidates), say in the case of [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 23 23] the first intermediary tie would overflow for largest == 0.
Also the second need not be faster, as you need to store into names and for every increase of largest. Almost a case of premature optimization.

Related

CS50 plurality - unable to print if there are too many winners

In plurality prblm, I managed to update votes for each candidate, my code can print the one winner, but still stuck if they are many winners .
help by hints or clues, not the whole solution.
Thanks in advance.
void print_winner(void)
{
int v = 0; //maximum number of votes
string w; //winner of the election
for (int i = 0; i < candidate_count; i++)
{
if (v <= candidates[i].votes)
{
v = candidates[i].votes;
}
}
for (int j = 0; j < candidate_count; j++)
{
if (candidates[j].votes == v)
{
w = candidates[j].name;
}
}
printf("%s\n", w);
return;
}
Change your second for loop to this:
for (int j = 0; j < candidate_count; j++)
{
if (candidates[j].votes == v)
{
w = candidates[j].name;
printf("%s\n", w);
}
}
You need to separate it into two for loops, if you have them together the first loop will run only through the first candidate with more than 1 vote and print it. Since it has not checked the others. That loops must finish and go through the whole set to actually find the max number of votes.
I am also on the same problem with you for around 2 or 3 days now. But I think I found out how to print if there are multiple winners.
First, I have a variable to store the highest votes and initialized it to 0. Then I tried comparing the candidates[i].votes against the current highest vote.
Then, I assigned the new value of the highest vote with the candidates vote until the loop finds someone who is higher than the previous one.
Lastly, I looped again through all the candidates and checks each candidates votes if they are equal to the highest vote. If yes, then their names should be printed. This solved my problem in printing 2 or more winners.

How to order a list of integers from greatest to least?

I have an assignment where I must use a structure to put in student information. I must then order the credit hours from greatest to least. I am focused on the integer ordering loop, I just can't figure out why my program is outputting incorrectly.
#include <stdlib.h>
#include <stdio.h>
struct Student {
char name[21];
int credits;
} s[99];
int main()
{
int students;
int tempCred = 0;
char tempName[21];
printf("How many students?: ");
scanf_s("%d", &students);
for (int i = 0; i < students; i++)
{
printf("\nStudent Name?: ");
scanf_s("%s", &s[i].name, 21);
printf("\nCredits Taken?: ");
scanf_s("%d", &s[i].credits);
}
for (int i = 0; i < students; i++) {
for (int j = 0; j < students; j++) {
if (s[j].credits > tempCred) {
tempCred = s[j].credits;
s[i].credits = s[j].credits;
s[j].credits = tempCred;
}
}
printf("\n%d", s[i].credits);
}
}
For example, if I were to enter 2,6, and 8 when asked for credit hours, the program would output '8,6,8'. I am not unfamiliar with sorting, but for some reason something isn't making sense when I look at this code. Could anyone help me order the integers from greatest to least? Thanks!
NOTE: I am aware there are better ways to do this, but my professor is making us use strictly C, no C++ at all. I just need help ordering the integers.
There are various techniques used for sorting. For instance the bubble sort, quick sort, insertion sort, etc. The simplest one is the bubble sort - but it's not the most efficient one.
In your program you have an array of structs. You've done the inserting part of the structs into the array and that's fine. The problem lies in the second part - the sorting. You have a for loop that starts at the very first element (i.e. 0) and goes all the way up to the last element (i.e. students-1). And nested inside this loop is another for loop - that also has the same range???
No, that's wrong. Instead replace the first and second for loops with this:
for (int i = 0 ; i < students-1 ; i++)
{
for (int j = i+1 ; j < students ; j++)
{
...
}
}
Here, the outer for loop begins with element 0 and goes up to the element before the last. The inner for loop starts with the next element to what the outer for loop stores (i.e. j = i + 1). So if i = 0, j = 1. And this loop goes all the way up to the last element of the array of structs.
Now, inside the inner for loop specify the condition. In your case you want them sorted in descending order (highest to lowest) of the credits.
for (int i = 0 ; i < students-1 ; i++)
{
for (int j = i+1 ; j < students ; j++)
{
if(s[j].credits > s[i].credits) // then swap the credits
{
tempCred = s[j].credits ;
s[j].credits = s[i].credits ;
s[i].credits = tempCred ;
}
}
}
Note that j is one greater that i. So if i = 0, j = 1, then the if statement reads
If the credits held in the struct in element 1 of the array is greater than the credits stored in the struct in element 0 of the array, then...
If the condition is met, the credits in these 2 structs are swapped.
This an implementation of the "bubble sort". See this for more techniques and explanations.
Finally, you can display the credits:
for(int index = 0 ; index < students ; index++)
{
printf("\n%d", s[index].credits) ;
}
Like a lot of people in the comments have said, use debugger. It'll help you trace the logic of your programs.
Like #Barmar said use the qsort() function from glibc.
Not only is easier than writting your own method but it is much faster at O(N log N) on average.

A function that returns 0 or 1 if all elements in the range 0 to n-1 exist in the array, run time O(n)

EDIT:
I forgot to mention that I do not want to allocate another temporarily array.
I am trying to solve a problem in C, which is:
Suppose you were given an array a and it's size N. You know that all of the elements in the array are between 0 to n-1. The function is supposed to return 0 if there is a missing number in the range (0 to n-1). Otherwise, it returns 1. As you can understand, duplicates are possible. The thing is that its supposed to run on O(n) runtime.
I think I managed to do it but i'm not sure. From looking at older posts here, it seems almost impossible and the algorithm seems much more complicated then the algorithm I have. Therefore, something feels wrong to me.
I could not find an input that returns the wrong output yet thou.
In any case, I'd appreciate your feedback- or if you can think of an input that this might not work for. Here's the code:
int missingVal(int* a, int size)
{
int i, zero = 0;
for (i = 0; i < size; i++)
//We multiply the element of corresponding index by -1
a[abs(a[i])] *= -1;
for (i = 0; i < size; i++)
{
//If the element inside the corresponding index is positive it means it never got multiplied by -1
//hence doesn't exist in the array
if (a[i] > 0)
return 0;
//to handle the cases for zeros, we will count them
if (a[i] == 0)
zero++;
}
if (zero != 1)
return 0;
return 1;
}
Just copy the values to another array placing each value in its ordinal position. Then walk the copy to see if anything is missing.
your program works and it is in O(N), but it is quite complicated and worst it modify the initial array
can be just that :
int check(int* a, int size)
{
int * b = calloc(size, sizeof(int));
int i;
for (i = 0; i != size; ++i) {
b[a[i]] = 1;
}
for (i = 0; i != size; ++i) {
if (b[i] == 0) {
free(b);
return 0;
}
}
free(b);
return 1;
}
This problem is the same as finding out if your array has duplicates. Here's why
All the numbers in the array are between 0 and n-1
The array has a size of n
If there's a missing number in that range, that can only mean that another number took its place. Which means that the array must have a duplicate number
An algorithm in O(n) time & O(1) space
Iterate through your array
If the sign of the current number is positive, then make it negative
If you found a negative this means that you have a duplicate. Since all items are originally greater (or equal) than 0
Implementation
int missingVal(int arr[], int size)
{
// Increment all the numbers to avoid an array with only 0s
for (int i = 0; i < size; i++) arr[i]++;
for (int i = 0; i < size; i++)
{
if (arr[abs(arr[i])] >= 0)
arr[abs(arr[i])] = -arr[abs(arr[i])];
else
return 0;
}
return 1;
}
Edit
As Bruno mentioned if we have an array with all zeros, we could have run into a problem. This is why I included in this edit an incrementation of all the numbers.
While this add another "pass" into the algorithm, the solution is still in O(n) time & O(1) space
Edit #2
Another great suggestion from Bruno which optimizes this, is to look if there's more than one zero instead of incrementing the array.
If there's 2 or more, we can directly return 0 since we have found a duplicate (and by the same token that not all the numbers in the range are in the array)
To overcome the requirement that excludes any extra memory consumption, the posted algorithm changes the values inside the array by simply negating their value, but that would leave index 0 unchanged.
I propose a different mapping: from [0, size) to (-1 - size, -1], so that e.g. {0, 1, 2, 3, 4, ...} becomes {-1, -2, -3, -4, -5, ...}. Note that, for a two's complement representation of integers, INT_MIN = -INT_MAX - 1.
// The following assumes that every value inside the array is in [0, size-1)
int missingVal(int* a, int size) // OT: I find the name misleading
{
int i = 0;
for (; i < size; i++)
{
int *pos = a[i] < 0
? a + (-a[i] - 1) // A value can already have been changed...
: a + a[i];
if ( *pos < 0 ) // but if the pointed one is negative, there's a duplicate
break;
*pos = -1 - *pos;
}
return i == size; // Returns 1 if there are no duplicates
}
If needed, the original values could be restored, before returning, with a simple loop
if ( i != size ) {
for (int j = 0; j < size; ++j) {
if ( a[j] < 0 )
a[j] = -a[j] - 1;
}
} else { // I already know that ALL the values are changed
for (int j = 0; j < size; ++j)
a[j] = -a[j] - 1;
}

Minimum number of steps required to reach the last index

Given an array of non-negative integers, you are initially positioned at the first index of the array.
Each element in the array represents your maximum jump length at that position.
Your goal is to reach the last index in the minimum number of jumps.
For example:
Given array A = [2,3,1,1,4]
The minimum number of jumps to reach the last index is 2. (Jump 1 step from index 0 to 1, then 3 steps to the last index.)
I have built a dp[] array from left to right such that dp[i] indicates the minimum number of jumps needed to reach arr[i] from arr[0]. Finally, we return dp[n-1].
Worst case time complexity of my code is O(n^2).
Can this be done in a better time complexity.
This question is copied from leetcode.
int jump(vector<int>& a) {
int i,j,k,n,jumps,ladder,stairs;
n = a.size();
if(n==0 || n==1)return 0;
jumps = 1, ladder = stairs = a[0];
for(i = 1; i<n; i++){
if(i + a[i] > ladder)
ladder = i+a[i];
stairs --;
if(stairs + i >= n-1)
return jumps;
if(stairs == 0){
jumps++;
stairs = ladder - i;
}
}
return jumps;
}
You can use a range-minimum segment tree to solve this problem. A segment tree is a data structure which allows you to maintain an array of values and also query aggregate operations on subsegments of the array. More information can be found here: https://cses.fi/book/book.pdf (section 9.3)
You will store values d[i] in the segment tree, d[i] is the minimum number of steps needed to reach the last index if you start from index i. Clearly, d[n-1] = 0. In general:
d[i] = 1 + min(d[i+1], ..., d[min(n-1, i+a[i])]),
so you can find all the values in d by computing them backwards, updating the segment tree after each step. The final solution is d[0]. Since both updates and queries on segment trees work in O(log n), the whole algorithm works in O(n log n).
I think, you can boost computing the dynamic with these technique:
You spend O(N) for compute current d[i]. But you can keep a set with d[j],
where j = 0..i - 1. And now all you need to use binary search to find:
such d[j], that is minimum among all(0..i-1) and from j position i-pos is reachable.
It will be O(n * logn) solution
That is a simple excercise in dynamic programming. As you have tagged it already, I wonder why you're not trying to apply it.
Let V[k] be the minimum number of steps to get from position k to the end of the list a = (a[0], a[1], ...., a[n-1]).
Then obviously V[n-1]=0. Now loop backwards:
for(int k=n-2;k>=0;--k)
{
int minStep = n + 1;
for(int j=k+1;j<=std::min(n-1,k+a[k]);++j)
{
minStep = std::min(minStep, V[j])
}
V[k]= minStep + 1;
}
Demo in C++
After the loop, which takes O(a[0]+a[1]+...+a[n-1]) time, V[0] contains the minimum number of steps to reach the end of the list.
In order to find the way through the list, you can then choose the action greedily. That is, from position k you always go to an allowed position l where V[l] is minimal.
(Note that I've assumed positive entries of the list here, not non-negative ones. Possible zeros can easily be removed from the problem, as it is never optimal to go there.)
https://leetcode.com/problems/jump-game-ii
class Solution {
public int jump(int[] nums) {
int n = nums.length;
if(n < 2){
return 0;
}
int ans = 1;
int rightBoundaryCovered = nums[0];
for(int i=1;i<n;i++){
if(rightBoundaryCovered >= n-1){
return ans;
}
int currMax = i+ nums[i];
while(rightBoundaryCovered>=i){
currMax = Math.max(currMax, i+nums[i]);
i++;
}
//missed this decrement statement and faced multiple WA's
i--;
ans++;
if(currMax>rightBoundaryCovered){
rightBoundaryCovered = currMax;
}
}
return ans;
}
}
Java solution (From Elements of Programming Interviews):
public boolean canJump(int[] nums) {
int maximumReach = 0;
for(int i = 0; i < nums.length; i++) {
// Return false if you jump more.
if(i > maximumReach) { return false; }
// Logic is we need to keep checking every index the
// farthest we can travel
// Update the maxReach accordingly.
maximumReach = Math.max(i + nums[i], maximumReach);
}
return true;
}

Finding an element repeating n times in 2n size array. Will this solution work?

I have an array which has 2n elements where n elements are same and remaining n elements are all different. There are lot of other complex algorithms to solve this problem.
Question: Does this approach give the same result or I am wrong somewhere?
#include<stdio.h>
main()
{
int arr[10],i,res,count=0;
printf("Enter the array elements:\t");
for(i=0;i<10;i++)
scanf("%d",&arr[i]);
for(i=0;i<8;i++)
{
if(arr[i]==arr[i+1] || arr[i]==arr[i+2])
{
res=arr[i];
break;
}
else if(arr[i+1]==arr[i+2])
{
res=arr[i+1];
break;
}
}
for(i=0;i<10;i++)
if(arr[i]==res)
count++;
if(count==5)
printf("true, no. repeated is:\t%d",res);
else printf("false");
return 0;
}
In addition to failing for the trivial 2 element case, it also fails for 4 elements in this case:
a b c a
I think the easiest way to solve this problem is to solve the majority element problem on a[1] ... a[2*N-1], and if no majority is found, then it must be a[0] if a solution exists at all.
One solution to the majority element problem is to scan through the array counting up a counter whenever the majority candidate element is encountered, and counting down the counter when a number different from the candidate is encountered. When the counter is 0, the next element is automatically considered the new candidate.
If the counter is positive at the end of the scan, the candidate is checked with another scan over the array. If the counter is 0, or the second scan fails, there is no majority element.
int majority (int a[], int sz) {
int i, count1 = 0, count2 = 0;
int candidate = -1;
for (i = 0; i < sz; ++i) {
if (count1 == 0) candidate = i;
count1 += ((a[candidate] == a[i]) ? 1 : -1);
}
if (count1 > 0) {
for (i = 0; i < sz; ++i)
count2 += (a[candidate] == a[i]);
}
if (count2 <= sz/2) candidate = -1;
return candidate;
}
Your algorithm will fail when the array has only 2 elements. It does not handle trivial case

Resources