Hackerrank: Climbing the Leaderboard - c#

i have a deal with a hackerrank algorithm problem.
It works at all cases, except 6-7-8-9. It gives timeout error. I had spent so much time at this level. Someone saw where is problem?
static long[] climbingLeaderboard(long[] scores, long[] alice)
{
//long[] ranks = new long[scores.Length];
long[] aliceRanks = new long[alice.Length]; // same length with alice length
long lastPoint = 0;
long lastRank;
for (long i = 0; i < alice.Length; i++)
{
lastPoint = scores[0];
lastRank = 1;
bool isIn = false; // if never drop in if statement
for (long j = 0; j < scores.Length; j++)
{
if (lastPoint != scores[j]) //if score is not same, raise the variable
{
lastPoint = scores[j];
lastRank++;
}
if (alice[i] >= scores[j])
{
aliceRanks[i] = lastRank;
isIn = true;
break;
}
aliceRanks[i] = !isIn & j + 1 == scores.Length ? ++lastRank : aliceRanks[i]; //drop in here
}
}
return aliceRanks;
}

This problem can be solved in O(n) time, no binary search needed at all. First, we need to extract the most useful piece of data given in the problem statement, which is,
The existing leaderboard, scores, is in descending order.
Alice's scores, alice, are in ascending order.
An approach that makes this useful is to create two pointers, one at the start of alice array, let's call it "i", and the second is at the end of scores array, let's call it "j". We then loop until i reaches the end of alice array and at each iteration, we check for three main conditions. We increment i by one if alice[i] is less than scores[j] because the next element of alice may be also less than the current element of scores, or we decrement j if alice[i] is greater than scores[j] because we are sure that the next elements of alice are also greater than those elements discarded in scores. The last condition is that if alice[i] == scores[j], we only increment i.
I solved this question in C++, my goal here is to make you understand the algorithm, I think you can easily convert it to C# if you understand it. If there are any confusions, please tell me. Here is the code:
// Complete the climbingLeaderboard function below.
vector<int> climbingLeaderboard(vector<int> scores, vector<int> alice) {
int j = 1, i = 1;
// this is to remove duplicates from the scores vector
for(i =1; i < scores.size(); i++){
if(scores[i] != scores[i-1]){
scores[j++] = scores[i];
}
}
int size = scores.size();
for(i = 0; i < size-j; i++){
scores.pop_back();
}
vector<int> ranks;
i = 0;
j = scores.size()-1;
while(i < alice.size()){
if(j < 0){
ranks.push_back(1);
i++;
continue;
}
if(alice[i] < scores[j]){
ranks.push_back(j+2);
i++;
} else if(alice[i] > scores[j]){
j--;
} else {
ranks.push_back(j+1);
i++;
}
}
return ranks;
}
I think this may help you too:
vector is like an array list that resizes itself.
push_back() is inserting at the end of the vector.
pop_back() is removing from the end of the vector.

Here is my solution with c#
public static List<int> climbingLeaderboard(List<int> ranked, List<int> player)
{
List<int> result = new List<int>();
ranked = ranked.Distinct().ToList();
var pLength = player.Count;
var rLength = ranked.Count-1;
int j = rLength;
for (int i = 0; i < pLength; i++)
{
for (; j >= 0; j--)
{
if (player[i] == ranked[j])
{
result.Add(j + 1);
break;
}
else if(player[i] < ranked[j])
{
result.Add(j + 2);
break;
}
else if(player[i] > ranked[j]&&j==0)
{
result.Add(1);
break;
}enter code here
}
}
return result;
}

Here is a solution that utilizes BinarySearch. This method returns the index of the searched number in the array, or if the number is not found then it returns a negative number that is the bitwise complement of the index of the next element in the array. Binary search only works in sorted arrays.
public static int[] GetRanks(long[] scores, long[] person)
{
var defaultComparer = Comparer<long>.Default;
var reverseComparer = Comparer<long>.Create((x, y) => -defaultComparer.Compare(x, y));
var distinctOrderedScores = scores.Distinct().OrderBy(i => i, reverseComparer).ToArray();
return person
.Select(i => Array.BinarySearch(distinctOrderedScores, i, reverseComparer))
.Select(pos => (pos >= 0 ? pos : ~pos) + 1)
.ToArray();
}
Usage example:
var scores = new long[] { 100, 100, 50, 40, 40, 20, 10 };
var alice = new long[] { 5, 25, 50, 120 };
var ranks = GetRanks(scores, alice);
Console.WriteLine($"Ranks: {String.Join(", ", ranks)}");
Output:
Ranks: 6, 4, 2, 1

I was bored so i gave this a go with Linq and heavily commented it for you,
Given
public static IEnumerable<int> GetRanks(long[] scores, long[] person)
// Convert scores to a tuple
=> scores.Select(s => (scores: s, isPerson: false))
// convert persons score to a tuple and concat
.Concat(person.Select(s => (scores: s, isPerson: true)))
// Group by scores
.GroupBy(x => x.scores)
// order by score
.OrderBy(x => x.Key)
// select into an indexable tuple so we know everyones rank
.Select((groups, i) => (rank: i, groups))
// Filter the person
.Where(x => x.groups.Any(y => y.isPerson))
// select the rank
.Select(x => x.rank);
Usage
static void Main(string[] args)
{
var scores = new long[]{1, 34, 565, 43, 44, 56, 67};
var alice = new long[]{578, 40, 50, 67, 6};
var ranks = GetRanks(scores, alice);
foreach (var rank in ranks)
Console.WriteLine(rank);
}
Output
1
3
6
8
10

Based on the given constraint brute-force solution will not be efficient for the problem.
you have to optimize your code and the key part here is to look up for exact place which can be effectively done by using binary search.
Here is the solution using binary search:-
static int[] climbingLeaderboard(int[] scores, int[] alice) {
int n = scores.length;
int m = alice.length;
int res[] = new int[m];
int[] rank = new int[n];
rank[0] = 1;
for (int i = 1; i < n; i++) {
if (scores[i] == scores[i - 1]) {
rank[i] = rank[i - 1];
} else {
rank[i] = rank[i - 1] + 1;
}
}
for (int i = 0; i < m; i++) {
int aliceScore = alice[i];
if (aliceScore > scores[0]) {
res[i] = 1;
} else if (aliceScore < scores[n - 1]) {
res[i] = rank[n - 1] + 1;
} else {
int index = binarySearch(scores, aliceScore);
res[i] = rank[index];
}
}
return res;
}
private static int binarySearch(int[] a, int key) {
int lo = 0;
int hi = a.length - 1;
while (lo <= hi) {
int mid = lo + (hi - lo) / 2;
if (a[mid] == key) {
return mid;
} else if (a[mid] < key && key < a[mid - 1]) {
return mid;
} else if (a[mid] > key && key >= a[mid + 1]) {
return mid + 1;
} else if (a[mid] < key) {
hi = mid - 1;
} else if (a[mid] > key) {
lo = mid + 1;
}
}
return -1;
}
You can refer to this link for a more detailed video explanation.

static int[] climbingLeaderboard(int[] scores, int[] alice) {
int[] uniqueScores = IntStream.of(scores).distinct().toArray();
int [] rank = new int [alice.length];
int startIndex=0;
for(int j=alice.length-1; j>=0;j--) {
for(int i=startIndex; i<=uniqueScores.length-1;i++) {
if (alice[j]<uniqueScores[uniqueScores.length-1]){
rank[j]=uniqueScores.length+1;
break;
}
else if(alice[j]>=uniqueScores[i]) {
rank[j]=i+1;
startIndex=i;
break;
}
else{continue;}
}
}
return rank;
}

My solution in javascript for climbing the Leaderboard Hackerrank problem. The time complexity of the problem can be O(i+j), i is the length of scores and j is the length of alice. The space complexity is O(1).
// Complete the climbingLeaderboard function below.
function climbingLeaderboard(scores, alice) {
const ans = [];
let count = 0;
// the alice array is arranged in ascending order
let j = alice.length - 1;
for (let i = 0 ; i < scores.length ; i++) {
const score = scores[i];
for (; j >= 0 ; j--) {
if (alice[j] >= score) {
// if higher than score
ans.unshift(count+1);
} else if (i === scores.length - 1) {
// if smallest
ans.unshift(count+2);
} else {
break;
}
}
// actual rank of the score in leaderboard
if (score !== scores[i-1]) {
count++;
}
}
return ans;
}

Here is my solution
List<int> distinct = null;
List<int> rank = new List<int>();
foreach (int item in player)
{
ranked.Add(item);
ranked.Sort();
ranked.Reverse();
distinct = ranked.Distinct().ToList();
for (int i = 0; i < distinct.Count; i++)
{
if (item == distinct[i])
{
rank.Add(i + 1);
break;
}
}
}
return rank;
This can be modified by removing the inner for loop also
List<int> distinct = null;
List<int> rank = new List<int>();
foreach (int item in player)
{
ranked.Add(item);
ranked.Sort();
ranked.Reverse();
distinct = ranked.Distinct().ToList();
var index = ranked.FindIndex(x => x == item);
rank.Add(index + 1);
}
return rank;

This is my solution in c# for Hackerrank Climbing the Leaderboard based on C++ answer here.
public static List<int> climbingLeaderboard(List<int> ranked, List<int> player)
{
List<int> _ranked = new List<int>();
_ranked.Add(ranked[0]);
for(int a=1; a < ranked.Count(); a++)
if(_ranked[_ranked.Count()-1] != ranked[a])
_ranked.Add(ranked[a]);
int j = _ranked.Count()-1;
int i = 0;
while(i < player.Count())
{
if(j < 0)
{
player[i] = 1;
i++;
continue;
}
if(player[i] < _ranked[j])
{
player[i] = j+2;
i++;
}
else
if(player[i] == _ranked[j])
{
player[i] = j+1;
i++;
}
else
{
j--;
}
}
return player;
}

My solution in Java for climbing the Leaderboard Hackerrank problem.
// Complete the climbingLeaderboard function below.
static int[] climbingLeaderboard(int[] scores, int[] alice) {
Arrays.sort(scores);
HashSet<Integer> set = new HashSet<Integer>();
int[] ar = new int[alice.length];
int sc = 0;
for(int i=0; i<alice.length; i++){
sc = 1;
set.clear();
for(int j=0; j<scores.length; j++){
if(alice[i] < scores[j] && !set.contains(scores[j])){
sc++;
set.add(scores[j]);
}
}
ar[i] = sc;
}return ar;
}

Related

returns the smallest positive integer (greater than 0) that does not occur in Array

I have the following question:-
Write a function:
class Solution { public int solution(int[] A); }
that, given an array A of N integers, returns the smallest positive integer (greater than 0) that does not occur in A.
For example, given A = [1, 3, 6, 4, 1, 2], the function should return 5.
Given A = [1, 2, 3], the function should return 4.
Given A = [−1, −3], the function should return 1.
Write an efficient algorithm for the following assumptions:
N is an integer within the range [1..100,000];
each element of array A is an integer within the range [−1,000,000..1,000,000].
now i tried this code:-
using System;
// you can also use other imports, for example:
// using System.Collections.Generic;
// you can write to stdout for debugging purposes, e.g.
// Console.WriteLine("this is a debug message");
class Solution
{
public int solution(int[] A)
{
// write your code in C# 6.0 with .NET 4.5 (Mono)
int n = 1;
Array.Sort(A);
for (int i = 1; i <= 100000; i++)
{
for (int i2 = 0; i2 <= A.Length - 1; i2++)
{
if (A[i2] == i)
{
n = A[i2] + 1;
break;
}
}
}
return n;
}
}
where my code worked well for these test data:-
A = [1, 2, 3]
A = [−1, −3]
while failed for this one:-
A = [1, 3, 6, 4, 1, 2] where it return 7 instead of 5.
any advice why my code failed on the 3rd test?
Thanks
using System.Linq;
int smallestNumber = Enumerable.Range(1, 100000).Except(A).Min();
I would use following approach that uses a HashSet<int> to check if a given integer is missing:
public static int? SmallestMissing(int[] A, int rangeStart = 1, int rangeEnd = 100_000)
{
HashSet<int> hs = new HashSet<int>(A);
for (int i = rangeStart; i <= rangeEnd; i++)
if(!hs.Contains(i)) return i;
return null;
}
A HashSet is a collection if unique values and it's very efficient in lookup items(complexity is O(1)). So you get a very readable and efficient algorithm at the cost of some memory.
Maybe you could optimize it by providing another algorithm in case the array is very large, you don't want to risk an OutOfMemoryException:
public static int? SmallestMissing(int[] A, int rangeStart = 1, int rangeEnd = 100_000)
{
if(A.Length > 1_000_000)
{
Array.Sort(A);
for (int i = rangeStart; i <= rangeEnd; i++)
{
int index = Array.BinarySearch(A, i);
if(index < 0) return i;
}
return null;
}
HashSet<int> hs = new HashSet<int>(A);
for (int i = rangeStart; i <= rangeEnd; i++)
if(!hs.Contains(i)) return i;
return null;
}
If you're allowed to sort the array in-place, which means modifying the input parameter value, here's a simple linear probe for the missing value (on top of the sort of course).
Here's the pseudo-code:
Sort the array
Skip all negatives and 0's at the start
Loopify the following:
Expect 1, if not found at current location return 1
Skip all 1's
Expect 2, if not found at current location return 2
Skip all 2's
Expect 3, if not found at current location return 3
Skip all 3's
... and so on for 4, 5, 6, etc. until end of array
If we get here, return currently expected value which should've been at the end
Here's the code:
public static int FirstMissingValue(int[] input)
{
Array.Sort(input);
int index = 0;
// Skip negatives
while (index < input.Length && input[index] < 1)
index++;
int expected = 1;
while (index < input.Length)
{
if (input[index] > expected)
return expected;
// Skip number and all duplicates
while (index < input.Length && input[index] == expected)
index++;
expected++;
}
return expected;
}
Test-cases:
Console.WriteLine(FirstMissingValue(new[] { 1, 3, 6, 4, 1, 2 }));
Console.WriteLine(FirstMissingValue(new[] { 1, 2, 3 }));
Console.WriteLine(FirstMissingValue(new[] { -1, -3 }));
output:
5
4
1
Your alg won't work in case input array becomes like this: [1,2-1,1,3,5]. I did this based on your alg. Give it a try:
int[] a = new int[] { -1, -2};
IEnumerable<int> uniqueItems = a.Distinct<int>().Where(x => x > 0);
if (uniqueItems.Count() == 0)
{
Console.WriteLine("result: 1");
}
else
{
Array asList = uniqueItems.ToArray();
Array.Sort(asList);
for (int i = 1; i <= 100000; i++)
{
if ((int)asList.GetValue(i - 1) != i)
{
Console.WriteLine("result: " + i);
break;
}
}
}
you can try like this.
public static int solution(int[] A)
{
int smallest = -1;
Array.Sort(A);
if(A[0] > 1)
return 1;
for(int i = 0; i < A.Length; i++)
{
if(A.Length != i+1 && A[i] + 1 != A[i + 1] && A[i+1] > 0)
{
smallest = A[i]+1;
break;
}
else if(A[i] > 0 && A.Length == i+1)
{
smallest = A[i] + 1;
}
}
return smallest > 0 ? smallest:1;
}
Here's the approach that uses O(N) partitioning followed by an O(N) search. This approach does not use any additional storage, but it DOES change the contents of the array.
This code was converted from here. Also see this article.
I've added comments to try to explain how the second stage findSmallestMissing() works. I've not commented the partitioning method, since that's just a variant of a standard partition as might be used in a QuickSort algorithm.
static class Program
{
public static void Main()
{
Console.WriteLine(FindSmallestMissing(1, 3, 6, 4, 1, 2));
Console.WriteLine(FindSmallestMissing(1, 2, 3));
Console.WriteLine(FindSmallestMissing(-1, -3));
}
public static int FindSmallestMissing(params int[] array)
{
return findSmallestMissing(array, partition(array));
}
// Places all the values > 0 before any values <= 0,
// and returns the index of the first value <= 0.
// The values are unordered.
static int partition(int[] arr)
{
void swap(int x, int y)
{
var temp = arr[x];
arr[x] = arr[y];
arr[y] = temp;
}
int pIndex = 0; // Index of pivot.
for (int i = 0; i < arr.Length; i++)
{
if (arr[i] > 0) // pivot is 0, hence "> 0"
swap(i, pIndex++);
}
return pIndex;
}
// This is the clever bit.
// We will use the +ve values in the array as flags to indicate that the number equal to that index is
// present in the array, by making the value negative if it is found in the array.
// This way we can store both the original number AND whether or not the number equal to that index is present
// in a single value.
//
// Given n numbers that are all > 0, find the smallest missing number as follows:
//
// For each array index i in (0..n):
// val = |arr[i]| - 1; // Subtract 1 so val will be between 0 and max +ve value in original array.
// if (val is in range) // If val beyond the end of the array we can ignore it
// and arr[val] is non-negative // If already negative, no need to make it negative.
// make arr[val] negative
//
// After that stage, we just need to find the first positive number in the array, which indicates that
// the number equal to that index + 1 is missing.
// n = number of values at the start of the array that are > 0
static int findSmallestMissing(int[] arr, int n)
{
for (int i = 0; i < n; i++)
{
int val = Math.Abs(arr[i]) - 1;
if (val < n && arr[val] >= 0)
arr[val] = -arr[val];
}
for (int i = 0; i < n; i++)
{
if (arr[i] > 0) // Missing number found.
return i + 1;
}
return n + 1; // No missing number found.
}
}
class Program
{
static void Main(string[] args)
{
int [] A = new int[] {1, 2, 3};
int n = 0;
bool found = false;
Array.Sort(A);
for (int i = 1; i <= 100000; i++) {
for (int x = 0; x <= A.Length - 1; x++) {
int next = (x + 1) < A.Length ? (x + 1): x;
if (A[x] > 0 && (A[next] - A[x]) > 0) {
n = A[x] + 1;
found = true;
break;
}
}
if(found) {
break;
}
}
Console.WriteLine("Smallest number: " + n);
}
}
int smallestNumber=Enumerable.Range(1,(int.Parse(A.Length.ToString())+1)).Except(A).Min();
Array.Sort(A);
for (int number = 1; number <= 100000; number++)
{
for (int num = number; i2 <= A.Length - 1; num++)
{
if (A[num] == number)
{
smallestNumber = A[num] + 1;
break;
}
}
}
return smallestNumber;
}
The easiest one :)
class Solution
{
public int solution(int[] array)
{
int[] onlyPositiveArray = array.Where(a => a > 0).OrderBy(a => a).Distinct().ToArray();
int smallestNumber = 1;
foreach (var number in onlyPositiveArray)
{
if (smallestNumber != number)
{
break;
}
smallestNumber ++;
}
if (!onlyPositiveArray.Contains(smallestNumber ))
{
return smallestNumber;
}
else
{
return smallestNumber + 1;
}
}
}
PHP Solution:
function solution($A) {
// write your code in PHP7.0
// sort array
sort($A);
// get the first
$smallest = $A[0];
// write while
while( in_array(($smallest),$A) || (($smallest) < 1 ) )
{
$smallest++;
}
return $smallest;
}
My solution, also if someone could test how performant it is?
public int solution(int[] N) {
if (N.Length == 0)
return 1;
else if (N.Length == 1)
return N[0] >= 0 ? N[0] + 1 : 1;
Array.Sort(N);
int min = Array.Find(N, IsUnderZero);
if (min ==
default)
return 1;
HashSet < int > hashSet = new HashSet < int > (N);
int max = N[N.Length - 1];
for (int i = min + 1; i <= max + 1; i++) {
if (!hashSet.Contains(i) && i > 0)
return i;
}
return max + 1;
bool IsUnderZero(int i) => i <= 0;
}
Try the below:
public static int MinIntegerGreaterThanZeroInArray(int[] A)
{
int minInt;
if (A.Length > 0)
{
Array.Sort(A);
for (minInt = 1; minInt <= A.Length; minInt++)
{
int index = Array.BinarySearch(A, minInt);
if (index < 0) return minInt;
}
return minInt;
}
//Array is empty.
throw new InvalidOperationException();
}
public static int Smallest(int[] A)
{
int maxPositiveInt = 1;
HashSet<int> NumDic = new HashSet<int>();
for (int i = 0; i < A.Length; i++)
{
if (A[i] <= 0)
{
continue;
}
if (!NumDic.Contains(A[i]))
{
NumDic.Add(A[i]);
}
maxPositiveInt = Math.Max(A[i], maxPositiveInt);
}
//All numbers are negative
if (NumDic.Count == 0)
{
return 1;
}
int smallestinteger = 1;
for (int i = 0; i < A.Length; i++)
{
if (A[i] <= 0)
{
continue;
}
if (!NumDic.Contains(smallestinteger))
{
return smallestinteger;
}
else
{
smallestinteger++;
}
}
return maxPositiveInt + 1;
}
static void Main(string[] args)
{
Console.WriteLine(solution(new int[]{1, 3, 6, 4, 1, 2}));
}
public static int solution(int[] A)
{
Array.Sort(A);
int smallest = A[0];
while (A.Contains(smallest+1)|| (smallest+1)<1)
{
smallest++;
}
return smallest +1;
}

How do we count the number of occurrence from left to right and continue until we have consecutive numbers?

So the code that I wrote, is for the number of occurrence. Suppose in the sample part which is mentioned, if I give an input Array of {2,1,1,1,3}, it will give me the count of Number 2 occurrence as 1. Now, I'm struggling to write the code in a manner so that it gives me the count only if it's continuous from left to right. Suppose, if my array is {1,1,1,2,0}, only then it will give me the total occurrence of 1 as 3, but not if it's {1,0,1,2,1} or {0,0,1,1,1} or {1,1,2,2,1}
static void Evaluate_V5B(int[] window, int[] PayCombos,)
{
int[] Counters1 = new int[3];
for (int index0 = 0; index0 < 5; index0++)
{
Console.Write("{0} ", window[index0]);
int symbol = window[index0];
Counters1[symbol]++;
}
Console.WriteLine();
for (int indexJ = 0; indexJ < Counters1.Length; indexJ++)
{
Console.WriteLine("{0}", Counters1[indexJ]);
}
}
This will take the 1st element in the array and return continuous occurrences from left to right. If that element found anywhere else it will return 0 as count:
static void Evaluate(int[] array)
{
var count = 1;
var first = array[0];
for (int i = 1; i < array.Length; i++)
{
if(array[i] == first)
{
count++;
}
else{
for (int j = i + 1; j < array.Length; j++)
{
if(first == array[j]) {
count = 0;
break;
}
}
break;
}
}
Console.WriteLine($"Count of Number {first} occurrence is {count}");
}
This function will find the number of continuous occurrences of a specific number num in the array nums, if it is the first number.
static int ContinuousOccurrences(int[] nums, int num)
{
if (nums[0] == num)
{
int continuousOccurrences =
nums.TakeWhile(x => x == num).Count();
int totalOccurrences =
nums.Where(x => x == num).Count();
if(continuousOccurrences == totalOccurrences)
{
return continuousOccurrences;
}
else
{
return 0;
}
}
return 0;
}
If you want to know the number of continuous occurrences of the first number, call the function this way:
ContinuousOccurrences(nums, nums[0])

Digit difference sort

So I am trying to solve this task "Digit Difference Sort" on Codefights
Given an array of integers, sort its elements by the difference of their largest and smallest digits.
In the case of a tie, that with the larger index in the array should come first.
Example
For a = [152, 23, 7, 887, 243], the output should be digitDifferenceSort(a) = [7, 887, 23, 243, 152].
Here are the differences of all the numbers:
152: difference = 5 - 1 = 4;
23: difference = 3 - 2 = 1;
7: difference = 7 - 7 = 0;
887: difference = 8 - 7 = 1;
243: difference = 4 - 2 = 2.
23 and 887 have the same difference, but 887 goes after 23 in a, so in the sorted array it comes first.
I have an issue with two numbers having the same difference. Here's what I wrote so far:
int[] digitDifferenceSort(int[] a) {
return a.OrderBy(x => difference(x)).ToArray();
}
int difference(int x)
{
int min = 9, max = 0;
do
{
int tmp = x % 10;
min = Math.Min(min, tmp);
max = Math.Max(max, tmp);
} while ((x /= 10) > 0);
return max - min;
}
Didn't do much (for example the output is still [7, 23, 887, 243, 152] rather than [7, 887, 23, 243, 152])
How do I make element with larger index come first in result? What should I use instead of OrderBy?
I don't consider your difference method, i assume it works fine.
To your question: you have to keep revered order of the array (that the items with the same difference arrive will be sorted reverse). To do it, you could just reverse you input array: all items with not identical difference will be ordered correctly, and with the same differece will be ordered reversed:
int[] digitDifferenceSort(int[] a)
{
return a.Reverse().OrderBy(x => difference(x)).ToArray();
}
Following is my code for the above question digit difference sort. I am also getting output when running in Eclipse but when I paste the code on code signal it gives me a null pointer exception.
package NormalPrograms;
import java.util.ArrayList;
import java.util.Collections;
public class DigitDifferenceSort {
// For index wise sorting in descending order
public static int[] sortingnumberindexwise(int[] a, ArrayList<Integer> index) {
int k = 0;
int[] res = new int[index.size()];
int[] finalres = new int[index.size()];
for (int i = a.length - 1; i >= 0; i--) {
for (int j = 0; j < index.size(); j++) {
if (a[i] == (int) index.get(j)) {
res[k] = i;
index.remove(j);
k++;
break;
}
}
}
int g = 0;
k = 0;
for (int i = 0; i < res.length; i++) {
finalres[g] = a[res[k]];
g++;
k++;
}
return finalres;
}
public static int[] finddigitDifferenceandSort(int[] p) {
int[] finres = new int[p.length];
for (int i = 0; i < finres.length; i++) {
finres[i] = p[i];
}
// This finres array act as an temp array and reused to make final result array
int digit = 0;
ArrayList<Integer> A = new ArrayList<Integer>();
ArrayList<ArrayList<Integer>> B = new ArrayList<ArrayList<Integer>>();
for (int i = 0; i < 10; i++) {
B.add(new ArrayList<Integer>());
}
for (int i = 0; i < p.length; i++) {
int temp = 0;
temp = p[i];
while (p[i] > 0) {
digit = p[i] % 10;
p[i] /= 10;
A.add(digit);
}
int b = Collections.max(A);
int c = Collections.min(A);
int diff = b - c;
B.get(diff).add(temp);
A.clear();
}
for (int i = 0; i < B.size(); i++) {
if (B.get(i).size() > 1) {
ArrayList<Integer> C = new ArrayList<Integer>();
for (int k = 0; k < B.get(i).size(); k++) {
C.add(B.get(i).get(k));
}
B.get(i).clear();
for (int j : sortingnumberindexwise(finres, C)) {
B.get(i).add(j);
}
} else {
continue;
}
}
int k = 0;
for (int i = 0; i < B.size(); i++) {
for (int j = 0; j < B.get(i).size(); j++) {
if (B.get(i).size() == 0)
continue;
else {
finres[k] = B.get(i).get(j);
k++;
}
}
}
return finres;
}
public static void main(String[] args) {
int[] a = { 12, 21, 1, 1, 1, 2, 2, 3 };
for (int i : finddigitDifferenceandSort(a)) {
System.out.print(i + " ");
}
}
}

Order an array in a specific order

I have this array of integers:-
int[] numbers = new int[] { 10, 20, 30, 40 };
I am trying to create an array which will have first element, last element, second element, second-last element and so on..
So, my resulting output will be:-
int[] result = {10,40,20,30};
This was my approach, in one loop start from first and go till the middle & in second loop start from last and get to the middle and select items accordingly, but I totally messed it up. Here is my attempted code:-
private static IEnumerable<int> OrderedArray(int[] numbers)
{
bool takeFirst = true;
if (takeFirst)
{
takeFirst = false;
for (int i = 0; i < numbers.Length / 2; i++)
{
yield return numbers[i];
}
}
else
{
takeFirst = true;
for (int j = numbers.Length; j < numbers.Length / 2; j--)
{
yield return numbers[j];
}
}
}
Need Help.
You might try this:
int[] result = numbers.Zip(numbers.Reverse(), (n1,n2) => new[] {n1, n2})
.SelectMany(x =>x)
.Take(numbers.Length)
.ToArray();
Explanation: This approach basically pairs up the elements of the original collection with the elements of its reverse ordered collection (using Zip). So you get a collection of pairs like [first, last], [second, second from last], etc.
It then flattens those collection of pairs into a single collection (using SelectMany). So the collection becomes [first, last, second, second from last,...].
Finally, we limit the number of elements to the length of the original array (n). Since we are iterating through twice as many elements (normal and reverse), it works out that iterating through n elements allow us to stop in the middle of the collection.
As a different approach, this is a modification on your existing method:
private static IEnumerable<int> OrderedArray(int[] numbers)
{
var count = (numbers.Length + 1) / 2;
for (int i = 0; i < count; i++)
{
yield return numbers[i];
int reverseIdx = numbers.Length - 1 - i;
if(i != reverseIdx)
yield return numbers[reverseIdx];
}
}
ok,
public static class Extensions
{
public static IEnumerable<T> EndToEnd<T>(this IReadOnlyList<T> source)
{
var length = source.Count;
var limit = length / 2;
for (var i = 0; i < limit; i++)
{
yield return source[i];
yield return source[length - i - 1];
}
if (length % 2 > 0)
{
yield return source[limit];
}
}
}
Which you could use like this,
var result = numbers.EndToEnd().ToArray();
more optimally,
public static class Extensions
{
public static IEnumerable<T> EndToEnd<T>(this IReadOnlyList<T> source)
{
var c = source.Count;
for (int i = 0, f = 0, l = c - 1; i < c; i++, f++, l--)
{
yield return source[f];
if (++i == c)
{
break;
}
yield return source[l];
}
}
}
no divide or modulus required.
With a simple for;
int len = numbers.Length;
int[] result = new int[len];
for (int i = 0, f = 0, l = len - 1; i < len; f++, l--)
{
result[i++] = numbers[f];
if (f != l)
result[i++] = numbers[l];
}
Based on Selman22's now deleted answer:
int[] numbers = new int[] { 10, 20, 30, 40 };
int[] result = numbers
.Select((x,idx) => idx % 2 == 0
? numbers[idx/2]
: numbers[numbers.Length - 1 -idx/2])
.ToArray();
result.Dump();
(The last line is LinqPad's way of outputting the results)
Or in less LINQy form as suggested by Jeppe Stig Nielsen
var result = new int[numbers.Length];
for (var idx = 0; idx < result.Length; idx++) {
result[idx] = idx % 2 == 0 ? numbers[idx/2] : numbers[numbers.Length - 1 -idx/2];
}
The principle is that you have two sequences, one for even elements (in the result) and one for odd. The even numbers count the first half of the array and the odds count the second half from the back.
The only modification to Selman's code is adding the /2 to the indexes to keep it counting one by one in the right half while the output index (which is what idx basically is in this case) counts on.
Came up with this
static void Main(string[] args)
{
List<int> numbers = new List<int>() { 10, 20, 30, 40, 50, 60, 70};
List<int> numbers2 = new List<int>();
int counter1 = 0;
int counter2 = numbers.Count - 1;
int remainder = numbers.Count % 2 == 0 ? 1: 0;
while (counter1-1 < counter2)
{
if (counter1 + counter2 % 2 == remainder)
{
numbers2.Add(numbers[counter1]);
counter1++;
}
else
{
numbers2.Add(numbers[counter2]);
counter2--;
}
}
string s = "";
for(int a = 0; a< numbers2.Count;a++)
s+=numbers2[a] + " ";
Console.Write(s);
Console.ReadLine();
}
This late answer steals a lot from the existing answers!
The idea is to allocate the entire result array at once (since its length is known). Then fill out all even-indexed members first, from one end of source. And finally fill out odd-numbered entries from the back end of source.
public static TElement[] EndToEnd<TElement>(this IReadOnlyList<TElement> source)
{
var count = source.Count;
var result = new TElement[count];
for (var i = 0; i < (count + 1) / 2; i++)
result[2 * i] = source[i];
for (var i = 1; i <= count / 2; i++)
result[2 * i - 1] = source[count - i];
return result;
}
Came up with this
public int[] OrderedArray(int[] numbers)
{
int[] final = new int[numbers.Length];
var limit=numbers.Length;
int last = numbers.Length - 1;
var finalCounter = 0;
for (int i = 0; finalCounter < numbers.Length; i++)
{
final[finalCounter] = numbers[i];
final[((finalCounter + 1) >= limit ? limit - 1 : (finalCounter + 1))] = numbers[last];
finalCounter += 2;
last--;
}
return final;
}

Find ascending duplicate pairs in an array

Given an array A with zero index and N integers find equal elements with different positions in the array. Pair of indexes (P,Q) such that 0 <= P < Q < N such that A[P] = A[Q]. My algorithm is below but I am looking for a O(N*logN) solution.
public int solution(int[] A)
{
int N = A.Length;
int count = 0;
for (int j = 0; j < N; j++)
{
count += FindPairs(A[j], j, A);
}
return count;
}
public int FindPairs(int item, int ci, int[] A)
{
int len = A.Length;
int counter=0;
int k = ci+1;
while (k < len)
{
if (item == A[k])
counter++;
k++;
}
return counter;
}
From your code, it looks like the goal is to return the count of ascending duplicate pairs in A.
We observe that if there are m occurrences of the number x in A, then the number of ascending duplicate pairs of the value x is m choose 2, or m (m - 1) / 2.
So, we sum up m (m - 1) / 2 for each unique x, giving us the answer.
In pseudocode, this looks like:
count = new Dictionary();
foreach a in A {
count[a]++;
}
total = 0;
foreach key, value in count {
total += value * (value - 1) / 2;
}
return total;
This algorithm is O(N).
Recent interview question … here is what I did:
using System;
using System.Collections.Generic;
using System.Linq;
namespace Codility
{
internal class Program
{
public struct Indice
{
public Indice(int p, int q)
{
P = p;
Q = q;
}
public int P;
public int Q;
public override string ToString()
{
return string.Format("({0}, {1})", P, Q);
}
}
private static void Main(string[] args)
{
// 0 1 2 3 4 5
int[] list = new int[] {3,3,3,3,3,3};
int answer = GetPairCount(list);
Console.WriteLine("answer = " + answer);
Console.ReadLine();
}
private static int GetPairCount(int[] A)
{
if (A.Length < 2) return 0;
Dictionary<int, Dictionary<Indice, Indice>> tracker = new Dictionary<int, Dictionary<Indice, Indice>>();
for (int i = 0; i < A.Length; i++)
{
int val = A[i];
if (!tracker.ContainsKey(val))
{
Dictionary<Indice, Indice> list = new Dictionary<Indice, Indice>();
Indice seed = new Indice(i, -1);
list.Add(seed, seed);
tracker.Add(val, list);
}
else
{
Dictionary<Indice, Indice> list = tracker[val];
foreach (KeyValuePair<Indice,Indice> item in list.ToList())
{
Indice left = new Indice(item.Value.P, i);
Indice right = new Indice(i, item.Value.Q);
if (!list.ContainsKey(left))
{
list.Add(left, left);
Console.WriteLine("left= " + left);
}
if (!list.ContainsKey(right))
{
list.Add(right, right);
Console.WriteLine("\t\tright= " + right);
}
}
}
}
return tracker.SelectMany(kvp => kvp.Value).Count(num => num.Value.Q > num.Value.P);
}
}
}
I think this is best version I got in c#.
static void Main(string[] args)
{
var a = new int[6] { 3, 5, 6, 3, 3, 5 };
//Push the indices into an array:
int[] indices = new int[a.Count()];
for (int p = 0; p < a.Count(); ++p) indices[p] = p;
//Sort the indices according to the value of the corresponding element in a:
Array.Sort(indices, (k, l) =>Compare(a[k], a[l]));
//Then just pull out blocks of indices with equal corresponding elements from indices:
int count = 0;
int i = 0;
while (i < indices.Count())
{
int start = i;
while (i < indices.Count() && a[indices[i]] == a[indices[start]])
{
++i;
}
int thisCount = i - start;
int numPairs = thisCount * (thisCount - 1) / 2;
count += numPairs;
}
Console.WriteLine(count);
Console.ReadKey();
}
//Compare function to return interger
private static int Compare(int v1, int v2)
{
if (v2 > v1)
return 1;
if (v1 == v2)
return 0;
else
return -1;
}
This approach has O(n log n) complexity overall, because of the sorting. The counting of the groups is linear.
Try this:
private static int GetIdenticalPairCount(int[] input)
{
int identicalPairCount = 0;
Dictionary<int, int> identicalCountMap = new Dictionary<int, int>();
foreach (int i in input)
{
if (identicalCountMap.ContainsKey(i))
{
identicalCountMap[i] = identicalCountMap[i] + 1;
if (identicalCountMap[i] > 1)
{
identicalPairCount += identicalCountMap[i];
}
else
{
identicalPairCount++;
}
}
else
{
identicalCountMap.Add(i, 0);
}
}
return identicalPairCount;
}
Test my version:
public int solution(int[] A)
{
int N = A.Length;
int count = 0;
for (int j = 0; j < N - 1; j++)
for (int i = j + 1; i < N; i++)
if (A[i] == A[j])
count++;
return count;
}

Categories

Resources