I'm practicing the cracking the code interview on my spare time.
The question states: Is Unique: Implement an algorithm to determine if a string has all unique character. What if you cannot use additional data structures?
The solution I found is: https://github.com/careercup/CtCI-6th-Edition-cpp/blob/master/Ch%201.Arrays%20And%20Strings/1.Is%20Unique/1.%20Is_unique.cpp
My implementation is:
bool UniqueCharsHash(string word) {
map<char, bool> uniqueChar; //keyType, valueType
for (int i = 0; i < word.length(); i++) {
char letter = tolower(word[i]);
if (!uniqueChar[letter]) {
uniqueChar[letter] = true;
} else {
return false;
}
}
return true;
}
//O(n^2) run time using a two loops (1 outer and 1 inner)
bool UniqueCharNoDS(string word) {
for (int i = 0; i < word.length() - 1; i++) {
for (int j = i + 1; j < word.length(); j++) {
if (word[i] == word[j]) {
return false;
}
}
}
return true;
}
but in the hint portion of the book it states:
try a hash table
could a bit vector be useful
can you solve it in O(Nlogn) time
I was wondering in the 3 methods shown, are any of those NlogN time?
As has often been pointed out, this question is solvable in O(1) because the longest string made up of unique characters is 256 characters long.
So when/if your algorithm hits the 257th character, it can stop and report "no".
Even if you use the naive algorithm of searching each character in the prefix up to that point, there are a maximum of 255*128 comparisons before the limit is reached. (No adjustment to the algorithm is necessary; it must report "no" on the 257th character if there is one.)
The below code (in Java) will determine if a string has all unique character.
Time complexity --> O(n)
final static int LETTERS_LEN = 256;
public static boolean isUnique(String str){
int[] letters = new int[LETTERS_LEN];
for (int i = 0; i < str.length(); i++) {
letters[str.charAt(i)]++;
}
for (int i = 0; i < LETTERS_LEN; i++) {
if (letters[i] > 1) {
return false;
}
}
return true;
}
This code solves it in O(NlogN) time, it is a modification of merge sort
boolean isUnique(char[] arr){
return sort(arr,0,arr.length-1);
}
// Merges two subarrays of arr[].
// First subarray is arr[l..m]
// Second subarray is arr[m+1..r]
boolean merge(char arr[], int l, int m, int r)
{
// Find sizes of two subarrays to be merged
int n1 = m - l + 1;
int n2 = r - m;
/* Create temp arrays */
char L[] = new char [n1];
char R[] = new char [n2];
/*Copy data to temp arrays*/
for (int i=0; i<n1; ++i)
L[i] = arr[l + i];
for (int j=0; j<n2; ++j)
R[j] = arr[m + 1+ j];
/* Merge the temp arrays */
// Initial indexes of first and second subarrays
int i = 0, j = 0;
// Initial index of merged subarry array
int k = l;
while (i < n1 && j < n2)
{
if (L[i] < R[j])
{
arr[k] = L[i];
i++;
}
else if(L[i] > R[j])
{
arr[k] = R[j];
j++;
}
else{
return false;
}
k++;
}
while (i < n1)
{
arr[k] = L[i];
i++;
k++;
}
/* Copy remaining elements of L[] if any */
while (j < n2)
{
arr[k] = R[j];
j++;
k++;
}
return true;
}
// Main function that sorts arr[l..r] using
// merge()
boolean sort(char arr[], int l, int r)
{
if (l < r)
{
// Find the middle point
int m = (l+r)/2;
// Sort first and second halves
boolean left= sort(arr, l, m);
boolean right = sort(arr , m+1, r);
// Merge the sorted halves
return left&&right&&merge(arr, l, m, r);
}
return true;
}
An O(n) time could be used with the hint (#2) provided. Where you shift bits and flip if a letter has already been seen.
static boolean isUniqueNoStruct(String input) {
// Length check
if (input.length() > 256)
return false;
// Assuming only lowercase 32 bit characters
int checkVal = 0;
for (int i = 0; i < input.length(); i++) {
int bit = input.charAt(i) - 'a';
// If the bit at the index has been flipped return false
if ((checkVal & ( 1 << bit)) > 0) {
return false;
}
checkVal |= (1 << bit);
}
return true;
}
Related
So this is my code which runs up till free(right); more like it completes merge sort then has an error, any solutions?
#include <stdio.h>
#include <stdlib.h>
void bubble_sort(int *l, int len) {
// Iterate through the list
for (int i = 0; i < len; i++) {
// Iterate through the list
for (int j = 0; j < len - 1; j++) {
// If the current element is greater than the next element, swap them
if (l[j] > l[j + 1]) {
// Swap the elements
int temp = l[j];
l[j] = l[j + 1];
l[j + 1] = temp;
// Print the list
for (int k = 0; k < len; k++) {
printf("%d ", l[k]);
}
printf("\n");
}
}
}
}
void selection_sort(int *l, int len) {
// Iterate through the list
for (int i = 0; i < len; i++) {
// Set the minimum index to the current index
int min_index = i;
// Iterate through the list
for (int j = i + 1; j < len; j++) {
// If the current element is less than the minimum element, set the minimum index to the current index
if (l[j] < l[min_index]) {
min_index = j;
}
}
// Swap the elements
int temp = l[i];
l[i] = l[min_index];
l[min_index] = temp;
// Print the list
for (int k = 0; k < len; k++) {
printf("%d ", l[k]);
}
printf("\n");
}
}
void insertion_sort(int *l, int len) {
// Iterate through the list
for (int i = 1; i < len; i++) {
// Set the current index to the current index
int j = i;
// While the current index is greater than 0 and the previous element is greater than the current element, swap them
while (j > 0 && l[j - 1] > l[j]) {
// Swap the elements
int temp = l[j - 1];
l[j - 1] = l[j];
l[j] = temp;
// Decrement the current index
j--;
}
// Print the list
for (int k = 0; k < len; k++) {
printf("%d ", l[k]);
}
printf("\n");
}
}
void merge(int *left, int left_len, int *right, int right_len) {
// Create a new list
int *result = malloc((left_len + right_len) * sizeof(int));
// Set the left index to 0 and the right index to 0
int i = 0;
int j = 0;
// While the left index is less than the length of the left list and the right index is less than the length of the right list
while (i < left_len && j < right_len) {
// If the left element is less than or equal to the right element, append the left element to the result list and increment the left index
if (left[i] <= right[j]) {
result[i + j] = left[i];
i++;
}
// Else, append the right element to the result list and increment the right index
else {
result[i + j] = right[j];
j++;
}
}
// Append the remaining elements in the left list to the result list
for (int k = i; k < left_len; k++) {
result[k + j] = left[k];
}
// Append the remaining elements in the right list to the result list
for (int k = j; k < right_len; k++) {
result[k + i] = right[k];
}
// Print the result list
for (int k = 0; k < left_len + right_len; k++) {
printf("%d ", result[k]);
}
printf("\n");
// Copy the result list to the original list
for (int k = 0; k < left_len + right_len; k++) {
left[k] = result[k];
}
// Free the result list
free(result);
}
void merge_sort(int *l, int len) {
// If the list is empty or has one element, return the list
if (len <= 1) {
return;
}
// Set the middle index to the length of the list divided by 2
int mid = len / 2;
// Set the left list to the first half of the list
int *left = malloc(mid * sizeof(int));
for (int i = 0; i < mid; i++) {
left[i] = l[i];
}
// Set the right list to the second half of the list
int *right = malloc((len - mid) * sizeof(int));
for (int i = mid; i < len; i++) {
right[i - mid] = l[i];
}
// Sort the left list
merge_sort(left, mid);
// Sort the right list
merge_sort(right, len - mid);
// Merge the left list and the right list
merge(left, mid, right, len - mid);
// Free the left list and the right list
free(left);
free(right); //Error ln 142, in picture below
}
int binary_search(int *l, int len, int target) {
// Set the low index to 0 and the high index to the length of the list minus 1
int low = 0;
int high = len - 1;
// While the low index is less than or equal to the high index
while (low <= high) {
// Set the middle index to the sum of the low index and the high index divided by 2
int mid = (low + high) / 2;
// If the middle element is equal to the target, return the middle index
if (l[mid] == target) {
return mid;
}
// Else if the middle element is less than the target, set the low index to the middle index plus 1
else if (l[mid] < target) {
low = mid + 1;
}
// Else, set the high index to the middle index minus 1
else {
high = mid - 1;
}
}
// If the target is not found, return -1
return -1;
}
int main() {
// Create a list
int l[] = {17, 36, 3, 10, 29, 42, 34, 8};
int len = sizeof(l) / sizeof(l[0]);
// Print the list
printf("Bubble Sort:\n");
// Sort the list using bubble sort
bubble_sort(l, len);
// Print the list
printf("Selection Sort:\n");
// Sort the list using selection sort
selection_sort(l, len);
// Print the list
printf("Insertion Sort:\n");
// Sort the list using insertion sort
insertion_sort(l, len);
// Print the list
printf("Merge Sort:\n");
// Sort the list using merge sort
merge_sort(l, len);
// Print the list
printf("Binary Search:\n");
// Search for the target in the list using binary search
printf("%d\n", binary_search(l, len, 42));
return 0;
}
So I rewrote the code from python to C, and debugging in GDB gives me the error in the screenshot.
GDB ss
I've tried to edit the function itself to rectify the memory issue but it wouldn't work so i reverted back to this and hope someone has some more insight.
The segfault is triggered in merge() used by merge_sort(). Everything else is irrelevant.
In merge_sort() you copy half of the input array l into a newly allocated array left and the other half into another newly allocated array right. Then recursively merge_sort() those two halves which is fine. To combine the two halves merge() is called where you incorrectly assume that the left and right arrays are allocated consecutively:
for (int k = 0; k < left_len + right_len; k++) {
left[k] = result[k];
}
The minimal fix is to make the assumption valid:
void merge_sort(int *l, int len) {
if (len <= 1) {
return;
}
int mid = len / 2;
int *left = malloc(len * sizeof(int));
for (int i = 0; i < mid; i++) {
left[i] = l[i];
}
int *right = left + mid;
for (int i = mid; i < len; i++) {
right[i - mid] = l[i];
}
merge_sort(left, mid);
merge_sort(right, len - mid);
merge(left, mid, right, len - mid);
free(left);
}
A even better resolution would be to:
Strictly separate the code under test and your test harness. In this case you want to delegate to main() the task of duplicating the input array instead of doing that in your sort algorithm. This allows merge_sort() to operate on the input array in-place (merge() still uses the temporary array).
Eliminate the right array pointer argument to merge(). This documents that the left and right arrays are part of the the same array.
Refactor the merge() and merge_sort() interface so the length argument is before the array argument so you can document how they relate.
(Not fixed). You could allocate the temporary space needed for merging once in merge_sort() and pass it to merge_sort2() and merge2(). That way you only have O(n) space overhead instead of O(n*log(n)). It is worth pointing out that malloc() may require a kernel context switch which in turn would be the most expensive operation th the merge() + merge_sort() implementation. Doing 1 instead of n*log(n) calls to malloc() could be a significant (constant) factor in run-time. Sharing the temporary space, however, comes a cost as you would no longer be able to do the otherwise non-overlapping merge sorts in parallel.
Prefer the type size_t to int for lengths. sizeof() in particular returns a size_t value, and the cast to the (signed) int will be problematic for sizes greater than INTMAX.
Prefer memcpy() instead of explicit loops when possible. memcpy() is highly optimized, and succinctly expresses intent.
Prefer passing a variable instead of a type to sizeof(). The former is robust if you change the type of the variable where the latter requires a code change if you didn't use a typedef for the type.
Finally, I added a print() function so you don't need the debug print statements in the sorting functions themselves.
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
void merge(size_t left_len, size_t right_len, int l[left_len + right_len]) {
int *result = malloc((left_len + right_len) * sizeof(*l));
int i = 0;
int j = 0;
while (i < left_len && j < right_len) {
if (l[i] <= l[left_len + j]) {
result[i + j] = l[i];
i++;
} else {
result[i + j] = l[left_len + j];
j++;
}
}
memcpy(result + i + j, l + i, (left_len - i) * sizeof(*l));
memcpy(result + left_len + j, l + left_len + j, (right_len - j) * sizeof(*l));
memcpy(l, result, (left_len + right_len) * sizeof(*l));
free(result);
}
void merge_sort(size_t len, int l[len]) {
if (len < 2) return;
int mid = len / 2;
merge_sort(mid, l);
merge_sort(len - mid, l + mid);
merge(mid, len - mid, l);
}
void print(size_t len, int a[len]) {
for(size_t i = 0; i < len; i++) {
printf("%d%s", a[i], i + 1 < len ? ", " : "\n");
}
}
int main() {
int l[] = {17, 36, 3, 10, 29, 42, 34, 8};
size_t len = sizeof(l) / sizeof(*l);
int l2[len];
memcpy(l2, l, sizeof(l));
merge_sort(len, l2);
print(len, l2);
}
and it returns:
3, 8, 10, 17, 29, 34, 36, 42
valgrind is happy:
ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
So I have two arrays consisting of double numbers, they are sorted.
I would like to most efficiently combine these into one array and have this one array also sorted.
My first thought was that maybe you could simply join them together then use qsort on it, but this wouldn't be that efficient. So maybe instead using merge sort? However, I am kind of lost on how to implement merge sort in C, any ideas?
I am using the code from one of the answers to try merge sorting. I have not made it into its own method just yet, will do that after I have gotten it to work.
double partitions[][5] = {{45.0, 5.0, 88.4, 0.4, 44.0}, {1000.0, 2.0, 3.4, 7.0, 50.0}};
double* res;
int n1 = sizeof(partitions[0])/sizeof(partitions[0][0]);
int n2 = sizeof(partitions[1])/sizeof(partitions[1][0]);
int n3 = n1 + n2;
res = malloc(n3 * sizeof(double));
// Merging starts
int i = 0;
int j = 0;
int k = 0;
while (i < n1 && j < n2) {
if (partitions[0][i] - partitions[1][j] < 0.000001) {
res[k] = partitions[0][i];
i++;
k++;
}
else {
res[k] = partitions[1][j];
k++;
j++;
}
}
/* Some elements in array 'arr1' are still remaining
where as the array 'arr2' is exhausted */
while (i < n1) {
res[k] = partitions[0][i];
i++;
k++;
}
/* Some elements in array 'arr2' are still remaining
where as the array 'arr1' is exhausted */
while (j < n2) {
res[k] = partitions[1][j];
k++;
j++;
}
int m;
for (m = 0; m < n3; m++)
printf("%f \n", res[m]);
Since the arrays are sorted you only need the merge part of the merge sort which is O(n1+n2) where n1 is the length of the one array and n2 is the length of the other array:
For example:
void merge(int n1, int n2){ //suppose global arrays arr1,arr2 and result array
i = 0;
j = 0;
k = 0;
// Merging starts
while (i < n1 && j < n2) {
if (arr1[i] <= arr2[j]) {
res[k] = arr1[i];
i++;
k++;
}
else {
res[k] = arr2[j];
k++;
j++;
}
}
/* Some elements in array 'arr1' are still remaining
where as the array 'arr2' is exhausted */
while (i < n1) {
res[k] = arr1[i];
i++;
k++;
}
/* Some elements in array 'arr2' are still remaining
where as the array 'arr1' is exhausted */
while (j < n2) {
res[k] = arr2[j];
k++;
j++;
}
}
Also I just note that your arrays contain double so you need to change the condition when comparing two numbers. For example instead of if (arr1[i] <= arr2[j]) you need to write a condition for: if (arr1[i] < arr2[j]) and then the else part.
I've looked around online for an non-recursive k-combinations algorithm, but have had trouble understanding all of the reindexing involved; The code I've found online is not commented well, or crashes.
For example, if I have the collection, {'a', 'b', 'c', 'd', 'e'} and I want to find a 3 combinations; ie,
abc
abd
abe
acd
ace
ade
bcd
bce
bde
cde
How can I implement an algorithm to do this? When I write down the general procedure, this it is clear. That is; I increment the last element in a pointer until it points to 'e', increment the second to last element and set the last element to the second to last element + 1, then increment the last element again until it reaches 'e' again, and so on and so forth, as illustrated by how I printed the combinations. I looked at Algorithm to return all combinations of k elements from n for inspiration, but my code only prints 'abc'. Here is a copy of it:
#include <stdio.h>
#include <stdlib.h>
static void
comb(char *buf, int n, int m)
{
// Initialize a pointer representing the combinations
char *ptr = malloc(sizeof(char) * m);
int i, j, k;
for (i = 0; i < m; i++) ptr[i] = buf[i];
while (1) {
printf("%s\n", ptr);
j = m - 1;
i = 1;
// flag used to denote that the end substring is at it's max and
// the j-th indice must be incremented and all indices above it must
// be reset.
int iter_down = 0;
while((j >= 0) && !iter_down) {
//
if (ptr[j] < (n - i) ) {
iter_down = 1;
ptr[j]++;
for (k = j + 1; k < m; k++) {
ptr[k] = ptr[j] + (k - j);
}
}
else {
j--;
i++;
}
}
if (!iter_down) break;
}
}
int
main(void)
{
char *buf = "abcde";
comb(buf, 5, 3);
return 1;
}
The very big problem with your code is mixing up indices and values. You have an array of chars, but then you try to increment the chars as if they were indices into the buffer. What you really need is an array of indices. The array of chars can be discarded, since the indices provide all you need, or you can keep the array of chars separately.
I found a psuedocode description here, http://www4.uwsp.edu/math/nwodarz/Math209Files/209-0809F-L10-Section06_03-AlgorithmsForGeneratingPermutationsAndCombinations-Notes.pdf
and implemented it in C by
#include <stdlib.h>
#include <stdio.h>
// Prints an array of integers
static void
print_comb(int *val, int len) {
int i;
for (i = 0; i < len; i++) {
printf("%d ", val[i]);
}
printf("\n");
}
// Calculates n choose k
static int
choose(int n, int k)
{
double i, l = 1.0;
double val = 1.0;
for (i = 1.0; i <= k; i++) {
l = ((double)n + 1 - i) / i;
val *= l;
}
return (int) val;
}
static void
comb(int n, int r)
{
int i, j, m, max_val;
int s[r];
// Initialize combinations
for (i = 0; i < r; i++) {
s[i] = i;
}
print_comb(s, r);
// Iterate over the remaining space
for (i = 1; i < choose(n, r); i++) {
// use for indexing the rightmost element which is not at maximum value
m = r - 1;
// use as the maximum value at an index, specified by m
max_val = n - 1; // use for
while(s[m] == max_val) {
m--;
max_val--;
}
// increment the index which is not at it's maximum value
s[m]++;
// iterate over the elements after m increasing their value recursively
// ie if the m-th element is incremented, all elements afterwards are
// incremented by one plus it's offset from m
// For example, this is responsible for switching 0 3 4 to 1 2 3 in
// comb(5, 3) since 3 and 4 in the first combination are at their maximum
// value
for (j = m; j < r - 1; j++) {
s[j + 1] = s[j] + 1;
}
print_comb(s, r);
}
}
int
main(void)
{
comb(5, 3);
return 1;
}
Given a very large integer array, I need to find the maximum value of a4, such that:
a4 = a1 + a2 + a3
Where the ai's are all values in the array.
How would I do this?
Note: Using 4 for loops is not the ideal solution.
There is a simple (expected) O(n^2) solution:
Iterate through all pairs of array elements (a, b) and store their sum in a hash table.
Iterate through all candidate pairs (a4, a1) and check whether a4 - a1 is in the table. The maximum over all valid a4 is the solution. Of course you should process a4 from largest to smallest, but that doesn't affect the asymptotics.
If you want to avoid using an element more than once, you need some additional information stored in the hash table so that you can filter out pairs that colide with a1 or a4 fast.
If the integers in the array are bounded (max - min <= C), it might be useful to know that you can achieve O(n + C log C) using a discrete fourier transform (solvable using FFT).
First of all you should ascending sort your array. then start from the last (biggest) member of the array.
For example, for [1,2,3,777,999,111,665] you'll have sortedArray = {1,2,3,111,665, 777, 999}
then select 999 as a4 and try to create it with other members. So you should select as a3 and try to create (999 - 777) = 222 as a1+a2 since your array is sorted you only need to consider subarray {1,2,3,111}. if there is no pair satisfying this condition, try next biggest member (777) and retry above scenario to find the solution
Based on #Niklas answer, I wrote the following program in Java.
public static int sumOfThree(int [] arr) {
int arrlen = arr.length;
int arrijv [][] = new int [arrlen * (arrlen - 1) / 2][3];
int arrijvlen = 0;
quickSortInDescendingOrder(arr, 0, arrlen - 1); // sorts array into descending order
System.out.println(Arrays.toString(arr));
// populates array with sum of all pair values
for (int i = 0; i < arrlen - 1; i++) {
for (int j = i + 1; j < arrlen; j++) {
// if ((arr[i] + arr[j]) < arr[0]) { // can be added if no negative values
arrijv[arrijvlen][0] = i;
arrijv[arrijvlen][1] = j;
arrijv[arrijvlen][2] = arr[i] + arr[j];
arrijvlen++;
// }
}
}
System.out.print('[');
for (int i = 0; i < arrijvlen; i++) {
System.out.print(arrijv[i][2] + " ");
}
System.out.print("]\n");
// checks for a match of difference of other pair in the populated array
for (int i = 0; i < arrlen - 1; i++) {
for (int j = i + 1; j < arrlen; j++) {
int couldBeA4 = arr[i];
if(isAvailable(arrijv, arrijvlen, couldBeA4 - arr[j], i, j)){
System.out.println(" i3-" + j + " i4-" + i);
return couldBeA4;
}
}
}
return -1;
}
private static boolean isAvailable(int[][] arrijv, int len, int diff, int i, int j) {
boolean output = false;
// returns true if the difference is matched with other combination of i,j
for (int k = 0; k < len; k++) {
if (arrijv[k][2] == diff) {
int pi = arrijv[k][0];
int pj = arrijv[k][1];
if (pi != i && pi != j && pj != i && pj != j) {
System.out.print("i1-" + pj + " i2-" + pi);
output = true;
break;
}
}
}
return output;
}
private static void quickSortInDescendingOrder(int[] array, int low, int high) { // solely used for sorting input array into descending array
if (low < high) {
int partition = getPartitionIndex(array, low, high);
quickSortInDescendingOrder(array, low, partition);
quickSortInDescendingOrder(array, partition + 1, high);
}
}
private static int getPartitionIndex(int[] arr, int lo, int hi) {
int pivot = arr[(lo + hi) / 2];
while (true) {
while (arr[lo] > pivot) {
lo++;
}
while (arr[hi] < pivot) {
hi--;
}
if (arr[lo] == arr[hi]) { // can be removed if no duplicate values
return lo;
} else if (lo < hi) {
int temp = arr[lo];
arr[lo] = arr[hi];
arr[hi] = temp;
} else {
return hi;
}
}
}
Please verify that it works and suggest for further improvements.
Consider a zero-indexed array A of N integers. Indices of this array are integers from 0 to N−1. Take an index K.
Index J is called an ascender of K if A[J] > A[K]. Note that if A[K] is a maximal value in the array A, then K has no ascenders.
Ascender J of K is called the closest ascender of K if abs(K−J) is the smallest possible value (that is, if the distance between J and K is minimal).
Note that K can have at most two closest ascenders: one smaller and one larger than K.
Here is a C++ solution where complexity is O(n).
Note that there are two loops however each iteration the number of element goes by a factor of 1/2 or the search range goes up by a factor of x2.
For example the first iteration take N time, but the second iteration is already N/2.
vector<long> ascender(vector <long> A)
{
long N = A.size();
vector<long> R(N,0);
vector<long> IndexVector(N,0); //This vector contains the index of elements with R=0
vector<long> RangeVector(N,0); //This vector define the loop range for each element
IndexVector[N-1]=N-1;
unsigned long CompxTest = 0;
for (long counter=0;counter<N;counter++)
{
IndexVector[counter] = counter; // we start that all elements needs to be consider
RangeVector[counter] = 1; // we start by looking only and neighbors
}
long Length = N;
long range;
while (Length>1)
{
long index = 0;
cout<<endl<<Length;
long J;
for (long counter=0;counter<Length;counter++)
{
CompxTest++; // Just to test complexity
J = IndexVector[counter]; // Get the index that need to be consider
range = RangeVector[J];
//cout<<" ("<<A[J]<<","<<J<<")";
if (range > N)
{
cout<<endl<<"Mini assert "<<range<<" N "<<N;
break;
}
if (J<(N-range) && A[J+range] > A[J])
{
R[J] = range;
}
if (J<(N-range) && A[J+range] < A[J] && R[J+range]==0)
{
R[J+range] = range;
}
if (J<(N-range) && A[J] == A[J+range] && R[J+range]==0)
{
R[J+range] = - range;
}
if (R[J]==0) // Didn't find ascender for this element - need to consider in next iteration
{
if (R[J+range]>2) //We can increase the range because the current element is smaller
RangeVector[J] += R[J+range]-2;
if (R[J+range]<-2)
RangeVector[J] += -R[J+range]-2;
RangeVector[J]++;
IndexVector[index] = J;
index++;
}
}
Length = index;
}
for (long counter=0;counter<N;counter++)
{
if (R[counter] < 0)
{
unsigned Value = abs(R[counter]);
if (counter+Value<N && A[counter]<A[counter+Value])
R[counter] = Value;
if (counter > Value && R[counter-Value]==0)
R[counter] = 0;
R[counter] = Value + R[counter-Value];
if (counter > Value && Value < R[counter - Value])
{
long PossibleSolution = R[counter - Value] + Value;
if (PossibleSolution <N && A[PossibleSolution]>A[counter])
R[counter] = abs(counter - PossibleSolution);
}
}
}
cout<<endl<<"Complex "<<CompxTest;
return R;
}
//
// C++ using multimap. -- INCOMPLETE
// The multimap MM is effectively the "inverse" of the input array AA
// since it is ordered by pair(value, index), where index refers to the index in
// input array AA, and value is the value in AA at that index.
// Input AA is of course ordered as (index, value).
// So when we read out of MM in value order, (a sorted set of values), each value
// is mapped to the index in the original array AA.
//
int ascender(int AA[], int N, int RR[]) {
multimap<int, int> MM;
// simply place the AA array into the multimap
int i;
for (i = 0; i < N; i++) {
int value = AA[i];
int index = i;
MM.insert(make_pair(value, index));
}
// simply read the multimap in order,
// and set output RR as the distance from one value's
// original index to the next value's original index.
//
// THIS code is incomplete, since it is wrong for duplicate values.
//
multimap<int, int>::iterator pos;
for (pos = MM.begin(); pos != MM.end(); ++pos) {
int value = pos->first;
int index = pos->second;
++pos;//temporarily move ahead to next item
// NEED to FURTHER CONSIDER repeat values in setting RR
RR[index] = (pos)->second - index;
--pos;
}
return 1;
}
1. Sort the array (if not pre-sorted)
2. Subtract every element with its adjacent element and store result in another
array.
Example: 1 3 5 6 8 -----> (after subtraction) 2 2 1 2
3. Find the minimal element in the new array.
4. Device a logic which would relate the minimal element in the new array to the
two elements in the original one.
public class Solution {
final static int MAX_INTEGER = 2147483647;
public static int maximal(int[] A) {
int max = A[0];
int length = A.length;
for (int i = 1; i < length; i++) {
if (A[i] > max) {
max = A[i];
}
}
return max;
}
public static int ascender(int[] a,int length, int k) {
int smallest = MAX_INTEGER;
int index = 0;
if (k<0 || k>length-1) {
return -1;
}
for (int i = 0; i < length; i++) {
// Index J is called an ascender of K if A[J] > A[K].
if(a[i] > a[k]) {
int abs = Math.abs(i-k);
if ( abs < smallest) {
smallest = abs;
index = i;
}
}
}
return index;
}
public static int[] array_closest_ascenders(int[] A) {
int length = A.length;
int[] R = new int[length];
for (int K = 0; K < length; K++) {
// Note that if A[K] is a maximal value in the array A,
// then K has no ascenders.
// if K has no ascenders then R[K] = 0.
if (A[K] == maximal(A)) {
R[K] = 0;
break;
}
// if K has the closest ascender J, then R[K] = abs(K-J);
// that is, R[K] is equal to the distance between J and K
int J = ascender(A, A.length, K);
if (J != -1) {
R[K] = Math.abs(K - J);
}
}
return R;
}
public static void main(String[] args) {
int[] a = { 4, 3, 1, 4, -1, 2, 1, 5, 7 };
/* int[] a = {-589630174, 806785750, -495838474, -648898313,
149290786, -798171892, 584782920, -288181260, -252589640,
133741336, -174886978, -897913872 }; */
int[] R = array_closest_ascenders(a);
for (int element : R) {
System.out.print(element + " ");
}
}
}
Some notes about the code. I guess break in array_closest_ascenders method should be replaced by continue so that all elements are analyzed for their ascenders.
And, surely, maximal(A) have to be moved out of a loop; instead assign maximal value to some variable before entering the loop and use it within the loop, thus avoiding redundant calculation of max value.
Here is C# Solution
class Program
{
static void Main(string[] args)
{
int[] A = new int[] { 4, 3, 1, 4, -1, 2, 1, 5, 7 };
int[] B = new int[A.Length];
int[] R = new int[A.Length];
Program obj = new Program();
obj.ABC(A,B, R);
}
public void ABC(int[] A,int[]B, int[] R)
{
int i, j, m,k;
// int temp = 0;
int n = A.Length - 1;
for (i = 0; i < n; i++)
{
for (j = 0; j <= n; j++)
{
if (A[i] < A[j])
{
m = Math.Abs(j - i);
R[i] = m;
break;
}
}
for (j = i-1; j > 0; j--)
{
if (A[i] < A[j])
{
k = Math.Abs(j - i);
B[i] = k;
break;
}
}
}
for (i = 0; i < n; i++)
{
if (R[i] > B[i] && (B[i] == 0))
{
R[i] = R[i];
//Console.WriteLine(R[i]);
//Console.ReadLine();
}
else { R[i] = B[i]; }
}
}
}
Basically in the search function I compare the first element of the array with the one immediately right, if it's bigger this means it is the first closest ascendant. For the other elements I compare the one immediately at left and afterward the one immediately right his first right element. The first one which is bigger is the closest ascendant, and I keep iterate this way until I don't find an element bigger than one I am considering or I return 0.
class ArrayClosestAscendent {
public int[] solution(int[] A) {
int i;
int r[] = new int[A.length];
for(i=0;i<A.length;i++){
r[i] = search(A, i);
}
return r;
}
public int search(int[] A, int i) {
int j,k;
j=i+1;
k=i-1;
int result = 0;
if(j <= A.length-1 && (A[j]>A[i]))
return Math.abs(j-i);
j++;
while(k>=0 || j < A.length){
if(k >= 0 && A[k] > A[i]){
return Math.abs(i-k);
}else if(j < A.length && A[j] > A[i]){
return Math.abs(i-j);
}else{
j++;
k--;
}
}
return result;
}
}