Write C code to initialize an array of 10 integers. If both sides of a number are smaller than it, then that number is the peak. Once you have all the peaks, create an array, store all the peaks in this new array and print them. The first question is I do not know how many peaks it may have, how to create the array to store peaks?
#include <stdio.h>
int main(void) {
int vals[10] = {1,2,3,1,4,6,3,8,9,1}; // initialize an array of 10 integers
int length = sizeof(vals) / sizeof(vals[0]);
int peaks;
for (int i = 1; i < length-1; i++) {
if (vals[i] > vals[i-1] && vals[i+1]) { // If both sides of a number are smaller than it
peaks[i] = vals[i];
}
printf("%d",peaks[i]);
return 0;
}
Just create an array the same size as the vals array. It's guaranteed that the number of peaks cannot be larger than the number of values. In reality the former will be much smaller than the latter as not every value can be a peak(1).
But, allowing for ten will be more than enough, without too much wastage.
Then you just use a variable to dictate how many peaks there are. For example, initialise the peak array as:
int peak[10];
size_t num_peaks = 0;
To add a peak to that array:
peak[num_peaks++] = new_peak;
And to process the peaks:
for (size_t peak_idx = 0; peak_idx < num_peaks; ++peak_idx)
do_something_with(peak[peak_idx]);
And, a couple of things to keep in mind:
Should you consider the first element to be a peak if the second is lower?
Ditto for the final element if the penultimate one is lower.
How do you handle plateaus (like 1, 3, 3, 2)? Neither of those 3 values are considered a peak under your current definition since the elements on either side are not both lower.
As a final suggestion, here is some Python code (you can convert it into C yourself, I tend to use Python as it's the ideal "pseudo-code" language) that will cater for what I believe is the best approach for finding peaks, by answering the questions above with:
Yes, first element can be a peak.
Yes, final element can also be a peak.
With plateaus, you effectively compress them into a single value and follow the normal rules, so 1, 3, 3, 2 is the same as 1, 3, 2.
The basic idea is to track the changes in direction (or gradient) so that you only consider it a peak when you switch from increasing to decreasing gradient. That can be achieved with the following code:
import random
def peaks(my_list):
# Edge case, no peaks for empty list.
if len(my_list) == 0: return []
# Peak accumulation list.
# Would be array for C as per my suggestions above.
my_peaks = []
# Start by assuming we're increasing to allow first element peak.
prev = my_list[0]
direction = "up"
# Process every item in list.
for item in my_list:
# If switching from rising to falling, that was a peak.
if item < prev and direction == "up":
my_peaks.append(prev)
direction = "down"
# If switching from falling to rising, that was a trough.
# Prepare to detect next peak.
elif item > prev and direction == "down":
direction = "up"
# Plateaus make no changes.
# Store previous to detect peak/trough.
prev = item
# If rising at end, it's considered a final peak.
if direction == "up":
my_peaks.append(prev)
return my_peaks
# This is a test harness to check results.
def find_peaks(my_list):
print(f"List: {my_list}")
print(f" -> {peaks(my_list)}\n")
find_peaks([])
find_peaks([1])
find_peaks([1, 2, 3])
find_peaks([3, 2, 1])
find_peaks([1, 2, 3, 3, 3, 3, 3, 2])
find_peaks([10, 9, 9, 9, 9, 8, 9])
find_peaks([1, 2, 1, 2, 1, 2, 1, 2, 1, 2])
for attempt in range(10):
count = 5 + random.randint(0, 10)
find_peaks([random.randint(5, 30) for _ in range(count)])
Hopefully, you'll see how this works from the comments and the following test output (I've inserted v characters to indicate the relevant peaks):
List: []
-> []
v
List: [1]
-> [1]
v
List: [1, 2, 3]
-> [3]
v
List: [3, 2, 1]
-> [3]
v
List: [1, 2, 3, 3, 3, 3, 3, 2]
-> [3]
vv v
List: [10, 9, 9, 9, 9, 8, 9]
-> [10, 9]
v v v v v
List: [1, 2, 1, 2, 1, 2, 1, 2, 1, 2]
-> [2, 2, 2, 2, 2]
vv vv vv vv
List: [30, 8, 7, 7, 29, 24, 15, 14, 7, 25, 17, 14, 27]
-> [30, 29, 25, 27]
vv vv vv vv
List: [10, 6, 16, 8, 18, 19, 25, 24, 18, 28]
-> [10, 16, 25, 28]
vv vv
List: [26, 13, 11, 13, 20, 17, 6, 6]
-> [26, 20]
vv vv vv vv vv
List: [17, 18, 30, 23, 14, 29, 17, 22, 22, 6, 15, 12, 11, 23]
-> [30, 29, 22, 15, 23]
vv vv vv
List: [26, 7, 16, 10, 23]
-> [26, 16, 23]
vv vv vv
List: [21, 12, 18, 14, 20]
-> [21, 18, 20]
vv vv vv
List: [27, 9, 13, 26, 15, 30]
-> [27, 26, 30]
vv vv vv
List: [11, 17, 21, 24, 26, 22, 16, 6, 7, 26, 16, 27]
-> [26, 26, 27]
vv vv vv vv
List: [12, 14, 9, 20, 21, 18, 6, 13, 10, 25, 5]
-> [14, 21, 13, 25]
vv vv
List: [17, 9, 30, 29, 7]
-> [17, 30]
This doesn't necessarily match your specific requirement that excludes the endpoints as possible peaks but that's fairly easy to adapt to by:
Starting the main loop with the second element rather than the first; and
Removing the final check for upward direction.
(1) The actual maximum number of peaks is about half the number of values, depending on how you define peak. With your current definition, the end points cannot be peaks since they have no values of the "other side" which can satisfy the "both sides of a number are smaller than it" requirement.
With the possibility that high values at the ends can be considered peaks, the maximum increases slightly.
With array sizes like ten, it's probably not worth worrying about the wastage of half the elements in the peaks array.
Once you have all the peaks, create an array...
Actually this implies a two-step approach. One pass to count the peaks, and a second to copy them into the new array.
At the same time it is misleading, because "having all the peaks" is not "determine the number of peaks".
Anyway, you can create an array at run-time with:
int *peaks = malloc(num_peaks * sizeof*peaks);
or simply as VLA:
int peaks[num_peaks];
(After obtaining num_peaks in a first run, in both cases)
On the other hand, this seems a bit complicated, since the first array has 10 integers by definition:
int length = sizeof(vals) / sizeof(vals[0]);
I would rather do this:
#define LENGTH = 10
int vals[LENGTH] = {1,2,3,1,4,
6,3,8,9,1};
Here vals is not a VLA, because LENGTH is turned into 10 at compile time.
You were so close. You set you loop limits correctly to allow you to check both sides of the current index in the vals[] array. By looping from 1 to length - 1 you can check the values at vals[i-1] and vals[i+1] each iteration. Neither end value can be a peak as there is no value on the opposite side to check.
However, after setting up your loop, you didn't check each side of vals[i] to determine if the current value was a peak. You need to do:
/* loop from 1 to length-1 checking value each side of current index */
for (int i = 1; i < length - 1; i++) {
if (vals[i-1] < vals[i] && vals[i] > vals[i+1]) { /* if peak */
...
Once you determine it is a peak, simply add vals[i] as the next element in the peaks[] array, e.g.
...
if (vals[i-1] < vals[i] && vals[i] > vals[i+1]) { /* if peak */
peaks[npeaks] = vals[i]; /* add value to peaks array */
npeaks += 1; /* increment no. of peaks */
}
}
A short example showing the complete program would be:
#include <stdio.h>
int main (void) {
int vals[] = {1,2,3,1,4,6,3,8,9,1},
length = sizeof vals / sizeof *vals,
peaks[sizeof vals] = {0}, /* create peaks array */
npeaks = 0; /* no. of peaks found */
/* loop from 1 to length-1 checking value each side of current index */
for (int i = 1; i < length - 1; i++) {
if (vals[i-1] < vals[i] && vals[i] > vals[i+1]) { /* if peak */
peaks[npeaks] = vals[i]; /* add value to peaks array */
npeaks += 1; /* increment no. of peaks */
}
}
puts ("peaks:"); /* output result */
for (int i = 0; i < npeaks; i++) {
printf (" peaks[%d] : %d\n", i, peaks[i]);
}
}
(note: when using sizeof with an expression, it is generally just sizeof expression, when using with a type (such as int), then it is generally sizeof(type), but note compilers will generally accept either sizeof(expression) or sizeof(type), but not sizeof type. See C11 Standard - 6.5.3 Unary operators)
Example Use/Output
$ ./bin/arrpeaks
peaks:
peaks[0] : 3
peaks[1] : 6
peaks[2] : 9
you can use this function to find the index of peak in an array and then you can print accordingly.
Using Binary Search.
int findPeakElement(int* nums, int numsSize) {
if(numsSize<=1) return 0;
int left=0;int right=numsSize-1;
int mid;
while(left!=right){
if(nums[left]>nums[left+1]) {
right=left;break;
}
else left+=1;
if(nums[right]>nums[right-1]){
left=right;break;
}
else right-=1;
mid=(right-left)/2+left;
if(nums[mid]<nums[mid+1])left=mid+1;
else right=mid;
}
return left;
}
Related
I'm trying to write a program whose input is an array of integers, and its size. This code has to delete the elements which are smaller than the element to the left. We want to find number of times that we have repeat this action to not be able to delete any more elements. Here is my code, it works but I want it to be faster.
Do you have any idea to make this code faster, or another way that is faster than this?
For example, given the array [10, 9, 7, 8, 6, 5, 3, 4, 2, 1], the function should return 2 because [10,9,7,8,6,5,3,4,2,1] → [10,8,4] → [10]
int numberOfTimes(int array[] , int n) {
int count = 0;
int flag = 0;
int sizeCounter = 0;
while (true){
for (int i = 0; i < n-1; ++i) {
if (array[i]<= array[i+1]){
sizeCounter++;
array[sizeCounter] = array[i+1];
} else{
flag = 1;
}
}
if (flag == 0)
return count;
count++;
flag = 0;
n = (sizeCounter+1);
sizeCounter = 0;
}
}
This problem can be solved in O(n) time and O(n) space using "monotonic stack".
For each element of the array we will find the number of "actions/turns" it takes to delete the element. In other words, how many turns have to pass, so that all elements between current element (inclusive) and the closest larger element to the left are deleted.
If we know that number (let's call it turns) then we can find maximum of this value for all elements of our array and we'll know the number of turns it takes to remove all elements from the array that can be removed. We'll have our answer.
Now, how do we find that turns value? It's easy, if we have these turns values computed for all elements to the left of the current element. We just find the closest element that is greater than current element and find the maximum number of turns for every element in between that element and the current element. I.e. if current element is at index i, and closest greater element is at index j (j < i and array[j] > array[i]), turns[i] = max(turns[k]+1), for k in [j+1..i-1].
If we do this naively, finding turns for each element would be O(n). Fortunately, it's easy to see, that when we've found j for some i, we won't ever need to consider elements between j and i ever again. Remember, array[j] > array[i] and everything in between j and i is smaller than array[i]. We're looking for the closest array element that is greater than some value, so, if array[i] is not an answer, the whole [j+1..i-1] range is also not an answer, we can go straight to j.
Having this in mind, we arrive to the monotonic stack. Instead of storing turns for every element of array, we store it only for the strictly decreasing subsequence of array that we've visited so far.
Before adding new element to the stack, first we need to remove every element that is smaller than the current element. Then the top of the stack will be our array[j].
As each element is added to the stack and removed exactly once, amortized cost of finding turns for each element is O(1), so the whole algorithm is O(n). In worst case the size of the stack grows to the same size as the array (if array is strictly decreasing). So the space complexity is O(n).
Here is the code (python):
array = [10, 9, 7, 8, 6, 5, 3, 4, 2, 1]
s = [] # monotonic stack of pairs (array[j],turns[j])
count = 0 # result: number of turns to delete all deletable elements
for el in array:
# initially assuming current element can be deleted
turns = 1
# peeking at the top of the stack
while len(s) > 0 and s[-1][0] <= el:
_,t = s.pop()
turns = max(t+1, turns)
# corner case: current element is the largest so far, cant be deleted
if len(s) == 0:
turns = 0
s.append( (el, turns) )
count = max(count, turns)
print(count)
Tests:
[10, 9, 7, 8, 6, 5, 3, 4, 2, 1] → 2
[10, 9, 7, 8, 6, 5, 3, 4, 2, 1, 9] → 3
[10, 9, 7, 8, 6, 5, 3, 4, 2, 1, 11] → 2
[] → 0
[1, 2, 3] → 0
[1, 2, 3, 1] → 1
[10, 1, 2, 3, 4, 5] → 5
UPD: I've just read the comments and I'd like to give kudos to #wLui155, who came up with the same core idea before me.
It's a very simple thing that I want to do in Minizinc. I have an array of integer values, and I want to know the number of times that the most common value in it occurs. I can't figure out how to do that. I hope someone can help.
I don't know if this is the most effective method, but it works, basically for each element in the array you sum the number of times that value appears in the array and store that in an auxliar array, and then take the find the maximum value that appears in the auxliar array, so in the example 14 appears 3 times so repeats holds 3 for every element corresponding to the 14.
At the end I added the one liner version of everything above, where instead of storing the array of repeats you generate it in place, its the line of max_repeats.
% count the number of times that the most common value is repeated in an array
% As an example lets make a 7 element array
% size
int : n = 7;
% index set
set of int : SET = 1..n;
% the values
array [SET] of int : x = [15,14,39,23,14,14,8];
% auxiliar variable to carry the count
array [SET] of var int : repeats;
% we will count the number of times that value repeats
constraint forall(i in SET)(repeats[i] = sum(j in SET)(x[i] = x[j]) );
% the value of the most repeated element in the array
var int : value;
% if the number of repeats of that element is the maximum
% then value is equal to that element
constraint forall(i in SET)(repeats[i] = max(repeats) -> value = x[i]);
% this does the same but in one line
var int : max_repeats = max([sum(j in SET)(x[i] = x[j]) | i in SET]);
solve satisfy;
output ["Original values " ++ show(x) ++ "\n"] ++
["Number of repeats of each element " ++ show(repeats) ++ "\n"] ++
["Maximum number of repeats : " ++ show(max(repeats))];
Original values [15, 14, 39, 23, 14, 14, 8]
Number of repeats of each element [1, 3, 1, 1, 3, 3, 1]
Maximum number of repeats : 3
The "classical" way of solving this problem is to use the global constriant global_cardinality together with max.
Below is one way to model this problem using these constraint; and it also shows the number that is the most frequent.
The drawback of using this approach is that one have to create a new array gcc (for "global cardinality count") which includes the number of occurrences for each number 0..upb (where upb is the upper bound of the array a), and that might be quite large if there are large numbers in the array. Also, one have to be a little careful about the indices, e.g. not forget to include 0 in gcc.
The advantage of this approach - apart from that is might be implemented efficient in a solver - is that one can add some extra constraints on the gcc array: here I added the the feature to show the number that is most frequent (using arg_max(a)); it might be more than one such numbers and will then give multiple solutions.
include "globals.mzn";
int: n = 7;
array[1..n] of int: a = [15, 14, 39, 23, 14, 14, 8];
% array[1..n] of var 0..29: a; % using decision variables
% upper value of a
int: upb = ub_array(a);
% Number of occurrences in a
array[0..upb] of var 0..n: gcc;
% max number of occurrenes
var 0..upb: z = max(gcc);
% The value of the max number of occurrences
var 0..upb: max_val = arg_max(gcc)-1;
solve satisfy;
constraint
% count the number of occurrences in a
global_cardinality(a, array1d(0..upb,[i | i in 0..upb]), gcc)
;
output [
"a: \(a)\n",
"upb: \(upb)\n",
"gcc: \(gcc)\n",
"z: \(z)\n",
"max_val: \(max_val)\n",
"ub_array(a): \(lb_array(a))..\(ub_array(a))\n",
];
Here is the output of this model:
a: [15, 14, 39, 23, 14, 14, 8]
upb: 39
gcc: [0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]
z: 3
max_val: 14
ub_array(a): 8..39
----------
==========
How do I use a for loop to add array 1 to array 2 and become the expected array like the example below?
What I expect is adding the first element in array 1 to array 2's second 1234 and continue adding up:
Array 1 = [4, 8]
Array 2 = [1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4]
Expected Array:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
I am thinking of something like this, but just feel very strange.
N=4
for (int i=N; i<array.size; i++)
{
array2[i] = array1[...];
}
I guess your question is when
int array1[] = {4, 8};
int array2[] = {1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4};
int arrayAnswer[] = {array2[0],array2[1],array2[2],array2[3],
array2[0]+array1[1],array2[1]+array1[1],array2[2]+array1[1],array2[3]+array1[1],
array2[0]+array1[2],array2[1]+array1[2],array2[2]+array1[2],array2[3]+array1[2]}
is it right? if so, please leave the comment and I will edit more
First of all, the question you made is not a good question. Please try to give more detailed information about your problem next time.
Answer for your question is, skip fist four member of array and add array1[1] on from array2[4] to array [7], and add array1[2] on from array2[8] to array [11]. You are going to need two loop. such as
for (i = 0; i < 2; i++){
for (j = 0; j < 4; j++){
//your function
}
}
I am not going to give you direct answer for the problem so that you can design your own. However, if your first array is {0, 4, 8}, your coding is going to be much easier. ty
I'm trying to optimize a prime search algorithm.
I have a program that finds (counts actually) primes below some limit. I know that prime number can be expressed in form 6k+1, 6k-1, for some k > 0.
For time present I use sieving algorithm to sort non-primes out. Some pseudo code :
int P[100] = {1};
int m = 100;
int n = 2, k, i, j, sqrtm = (int)sqrt(m);
for(k = 2, i = 5; i < sqrtm + 1; i += k, k ^= 6)
if(P[i])
P[i] = 0;
n = n + 1;
for(j = i * i; j < m; j += 2 * i)
P[j] = 0;
for(k = 2, i = 5; i < m + 1; i += k, k ^= 6)
if(P[i])n = n + 1;
print n;
Above code hopefully prints number of primes below number m.
I'm using some tricks here and there to speed things up. For example, starting sieving non-primes from '5', use the fact, that prime number in above form can't be multiples of '2' and '3'. 6k + 2 is even. 6k + 3 is multiple of '3', let x = 2k, 6k + 3 => 3x + 3 => 3(x + 1) mod 3 == 0, or 3(2k + 1) mod 3 == 0.
Here, my question arises. If I make a pre-sieve with some primes, can I take a different form of prime number to speed up sieving loop ?
For example, pre-sieve with 2,3,5,7,11,13,17,19,23,29. So, now P array has no multiples of of above. Maybe one can suggest me some form of prime number form, such, that with pre-sieving, loop can be done is larger chunks.
I've already done some, non related to prime number form, optimizations. Like sieving in chunks and using bit set to store sieve. All that made my program to run pretty fast.
time ./np 1000000000
allocated 119Mb
primes from 2 <= 1000000000 : 50847534
real 0m2.386s
user 0m2.354s
sys 0m0.032s
I know I can get better prime number counter program from the internet. And it will run faster. But I just want to know how far I can go by myself. And community help ;)
To sum things up. I want to use a pre-sieving. I think that it gets me less comparisons plus less inner loops total. I ask you, how to write prime number in other form, knowing the pre-sieving fact?
You say that, other than 2 and 3, all prime numbers have the form 2*3*k±1 (for some integer k>=1)
You can extend that to
2*3*5*k ±{1, 7, 11, 13} (and 2, 3, 5, 7, 11, 13)
or
2*3*5*7*k ±{1, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109} (and 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97)
Implementing this forms may not make your program more efficient (however you define efficient). You need to measure.
Values above were typed directly from mobile without validation. Use at your own risk.
This question already has answers here:
Unique random number generation in an integer array [duplicate]
(9 answers)
Closed 4 years ago.
So i'm trying to create an array of 4 items that is randomly filled with 4 unique numbers. Currently I have a hugely long while loop which checks each value in the array and keeps repeating if they are the same. It's really badly coded and I was wondering if you guys could help me figure out a better way?
Here's what I currently have.
int array[4];
while(array[0] == array[1] || array[1] == array[2] || array[2] == array[3] || array[0] == array[2] || array[0] == array[3] || array[1] == array[3])
{
array[0] = rand() % 20;
array[1] = rand() % 20;
array[2] = rand() % 20;
array[3] = rand() % 20;
}
Here's an algorithm to generate your array of 4 distinct numbers from 0 to 20 which is O(n + m) with n the 4 numbers and m the 20 possible values:
Create an array randArr of 20 integers: {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19}. This is the array used to pick random numbers
array is an array of 4 integers that will contain the result
for i going from 0 to 3 (included):
Pick a random number r between i and 19 (inclusive). Swap randArr[r] and randArr[i]
Copy to array: array[i] = randArr[i]
Here's the implementation (with a slight improvement to merge the last 2 steps):
int randArr[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19};
int array[4];
for (int i = 0; i < 4; i++) {
int r = i + rand() % (20 - i);
array[i] = randArr[r];
randArr[r] = randArr[i];
}
https://tech.io/snippet/dGgblEO
You want generate random numbers from 0 to 19 and fill them in the array without any duplicates.
Since you have not initialized the elements of array, it is possible that the uninitialized values are already distinct from each other. In this case, the while loop will not be executed at all.
Secondly, you are generating random values for every element of the array every time when any two of them match. This is not required. You have to regenerate the random number only for the element that matches any of the existing ones. This is what a set structure (mentioned in the comments) does.
To shuffle an array of n elements, Fisher–Yates shuffle Algorithm is used which works in O(n) time complexity.
In your case, take an initial array of values from 0 to 19. Once you have shuffled this array, you can take the any k elements of this array (in your case k = 4) and use them (They will be distinct). Implementations of this algorithm can be found online.