On the Wikipedia page about Counting Sort, it states:
It is possible to modify the algorithm so that it places the items into sorted order within the same array that was given to it as the input, using only the count array as auxiliary storage; however, the modified in-place version of counting sort is not stable.
I am curious about how such algorithm is implemented, but I don't have access to the source cited. Could somebody explain how it works?
After counting, you have an array of counts for each value, say:
[4,3,1,2]
Shift it to the right:
[0,4,3,1]
With a cumulative sum, change this into an array of the start positions for each value in the sorted result:
[0,4,7,8]
Now you walk through the array, swapping each each item into place at the start position for its value, and incrementing the start position so the next one will go in the right place, but ONLY if the item belongs the same or earlier position. If it belongs in a later position, then just skip it, and the item that belongs there will be swapped in when we get to it (because it must belong in the earlier position).
Swapping will bring a new element into the target position, so repeat at the same position until you find one that isn't swapped.
Here's the algorithm in JavaScript, using values from 0 to 9:
const len = 25;
const array = [];
for (let i=0; i<len; ++i) {
array.push(Math.floor(Math.random()*10));
}
console.log("Original array:", String(array));
const cp = [0,0,0,0,0,0,0,0,0,0];
for (const val of array) {
++cp[val];
}
console.log("Counts:", String(cp));
for (let i=cp.length-1; i>0; --i) {
cp[i] = cp[i-1];
}
cp[0]=0;
for (let i=1; i<cp.length; ++i) {
cp[i]+=cp[i-1];
}
console.log("Start pointers: ", String(cp));
let pos=0;
while(pos < array.length) {
let v = array[pos];
let dest = cp[v];
if (dest <= pos) {
if (dest < pos) {
// v belongs at an earlier position. Swap it into place
array[pos] = array[dest];
array[dest] = v;
} else {
// v belongs at the same position. don't visit it again
++pos;
}
// increment the pointer for this value
cp[v] = dest+1;
} else {
// v belongs at a later position. Something later must belong here.
// Skip it and let the later item swap in when we get there
++pos;
}
}
console.log("Sorted array:", String(array));
Totally untested C++ code
#include <array>
#include <vector>
#include <algorithm>
#include <numeric>
void counting_sort(std::vector<uint8_t>& values) {
std::array<uint8_t , 256> count;
for(auto& value : values)
count[value]++; // count
std::partial_sum(count.begin(), count.end(), count.begin()); // sum
std::array<uint8_t , 256> position;
position[0] = 0; // first position of first value
std::copy_n(count.begin(), count.size()-1, std::next(position.begin())); // moved by one
int pos = 0;
while (pos < count.size()) {
while (count[pos] > position[pos]) {
auto& from = position[pos]; // current position
auto& to = position[values[from]]; // final position
if (to != from)
std::swap(values[from], // from current position
values[to]); // where the value needs to go
to++; // update destination position
}
pos++;
}
}
In the while with the swap you keep swapping until the value that should be place in the first position is swapped into that position.
0 // pos
[3,2,1] // values
[0,1,1,1] // count
[_0_,1,2,3] // count
[_0_,0,1,2] // position
1 // pos
[0,_1_,2,3] // count
[0,_0_,1,2] // position
values[position[pos]] -> 3
position[3] -> 2
position[pos] -> 0
[_3_,2,_1_]
swap
[1,2,3]
position[values[pos]]++
[0,0,1,_2_] // position
[0,0,1,_3_] // position
1 // pos
[0,_1_,2,3] // count
[0,_0_,1,3] // position
values[position[pos]] -> 1
position[1] -> 0
position[pos] -> 0
positions are the same so update to
[0,_0_,1,3] // position
[0,_1_,1,3] // position
[0,_1_,2,3] // count
[0,_1_,1,3] // position
update pos
pos = 2
[0,1,_2_,3] // count
[0,1,_1_,3] // position
positions are the same to update to
[0,1,_1_,3] // position
[0,1,_2_,3] // position
count&position are the same so update pos
pos = 3
count&position are the same so update pos
pos = 4
done
Related
I am working on an assignment for DS and Algo I am given two sorted integer lists or arrays then I have to merge them into one list. I decided to use two queues for each array by putting each element in the queue then do some comparisons and put them into a singly linked list. Now the problem I have faced is that it is only printing the first element over and over again in the first array. My goal is to put remove the elements in the queue and put them in a linked list from least to greatest.
Also the count in the while loop is used to stop the loop once it equals the length of both arrays - 1.
MergeQueue.java
int[] A = {1, 3, 5, 7, 9}; // our first array A
int[] B = {2, 3, 6, 8, 10}; // our second array B
int length = A.length + B.length - 1; // get the length of both A and B
//System.out.println(length);
int count = 0; // this is a counter used to check that once count is equal to the length(A+B) then we break the loop
int frontA, dequeueA;
int frontB, dequeueB;
// we can use a singly linked list to store elements of A and B
SingleLinkedList S = new SingleLinkedList();
QueueLinkList queueA = new QueueLinkList(); // our queue for A type integer
QueueLinkList queueB = new QueueLinkList(); // our queue for B type integer
// Add elements from A to the queue
for(int i = 0; i < A.length; i++) {
// so add element from A to the queue
queueA.enqueue(A[i]);
}
// Add elements from B to the queue
for(int i = 0; i < B.length; i++) {
// so add element from B to the queue
queueB.enqueue(B[i]);
}
// now begins the conditions
while(count != length) {
// only return the element in the front not remove it
frontA = queueA.front();
frontB = queueB.front();
if(frontA < frontB) {
dequeueA = queueA.dequeue(); // remove the element and add it to the linked list
// add dequeueA to list S
S.add(dequeueA); // add the element to the singly linked list
count++; // increment the counter
}
else if(frontB < frontA) {
dequeueB = queueB.dequeue();
// add dequeueB to list S
S.add(dequeueB); // add the element to the singly linked list
count++; // increment the counter
}
// if the elements are the same then remove from queue and add anyone.
else if(frontA == frontB || frontB == frontA) {
dequeueA = queueA.dequeue();
dequeueB = queueB.dequeue();
// add either dequeueA or B
S.add(dequeueA); // add the element to the singly linked list
count++; // increment the counter
}
// if queue A is empty and queue B is not then add remaining elements from B to S.
else if(queueA.isEmpty() && !queueB.isEmpty()){
// add remaining elements from B to the list
dequeueA = queueA.dequeue();
S.add(dequeueA);
count++; // increment the counter
}
// if queue B is empty and queue A is not then add remaining elements from B to S.
else if(queueB.isEmpty() && !queueA.isEmpty()) {
// add remaining elements from B to the list
dequeueB = queueB.dequeue();
S.add(dequeueB);
count++;
}
}
System.out.println("Our set S:");
S.print(); // call the print method which displays every element in the singly linked list
In this part of code
else if(frontA == frontB || frontB == frontA) {
dequeueA = queueA.dequeue();
dequeueB = queueB.dequeue();
// add either dequeueA or B
S.add(dequeueA); // add the element to the singly linked list
count++; // increment the counter
}
You need to increment count by 2 times since even though you are adding in link list once you are removing same element from both the queue and hence two elements are getting removed
Suppose you need to count the number of islands on a matrix
{1, 1, 0, 0, 0},
{0, 1, 0, 0, 1},
{1, 0, 0, 1, 1},
{0, 0, 0, 0, 0},
{1, 0, 1, 0, 1}
We could simply use DFS or BFS when the input matrix size can be fitting into the memory.
However, what do we do if the input matrix is really large which could not be fitting into the memory?
I could chunk/split the input matrix into different small files and read them respectively.
But how to merge them?
I got stuck at how to merge them. I have the idea that when merging them we have to read some overlapped portion. But what is a concrete way to do so?
Trying to understand Matt's solution.
When I drew the below sample on the whiteboard and process it row by row.
Merge left then merge top and it seems won't work.
From Matt's solution.
not sure what are topidx, botidx meaning
int topidx = col * 2;
int botidx = topidx + 1;
Using union-find, the basic algorithm (without worrying about memory) is:
Create a set for every 1
Merge the sets for every pair of adjacent 1s. It doesn't matter what order you find them in, so reading order is usually fine.
Count the number of root sets -- there will be one for every island.
Easy, and with a little care, you can do this using sequential access to the matrix and only 2 rows worth of memory:
Initialize the island count to 0
Read the first row, create a set for each 1, and merge sets in adjacent columns.
For each additional row:
Read the row, create a set for each 1, and merge sets in adjacent columns;
Merge sets in the new row with adjacent sets in the previous row. ALWAYS POINT THE LINKS DOWNWARD, so that you never end up with a set in the new row linked to a parent in the old row.
Count the remaining root sets in the previous row, and add the number to your island count. These will never be able to merge with anything else.
Discard all the sets in the previous row -- you're never going to need them again, because you already counted them and nothing links to them.
Finally, count the root sets in the last row and add them to your island count.
The key to this, of course, is always pointing the links downward whenever you link sets in different rows. This will not hurt the complexity of the algorithm, and if you're using your own union-find, then it is easy to accomplish. If you're using a library data structure then you can use it just for each row, and keep track of the links between root sets in different rows yourself.
Since this is actually one of my favorite algorithms, here is an implementation in Java. This is not the most readable implementation since it involves some low-level tricks, but is super-efficient and short -- the kind of thing I'd write where performance is very important:
import java.util.Arrays;
public class Islands
{
private static final String[] matrix=new String[] {
" ############# ### ",
" # ##### ## ",
" # ## ## # # ",
" ### ## # # ",
" # ######### ## ## ",
" ## ## ",
" ########## ",
};
// find with path compression.
// If sets[s] < 0 then it is a link to ~sets[s]. Otherwise it is size of set
static int find(int[] sets, int s)
{
int parent = ~sets[s];
if (parent>=0)
{
int root = find(sets, parent);
if (root != parent)
{
sets[s] = ~root;
}
return root;
}
return s;
}
// union-by-size
// If sets[s] < 0 then it is a link to ~sets[s]. Otherwise it is size of set
static boolean union(int[] sets, int x, int y)
{
x = find(sets,x);
y = find(sets,y);
if (x!=y)
{
if ((sets[x] < sets[y]))
{
sets[y] += sets[x];
sets[x] = ~y;
}
else
{
sets[x] += sets[y];
sets[y] = ~x;
}
return true;
}
return false;
}
// Count islands in matrix
public static void main(String[] args)
{
// two rows of union-find sets.
// top row is at even indexes, bottom row is at odd indexes. This arrangemnt is chosen just
// to make resizing this array easier.
// For each value x:
// x==0 => no set. x>0 => root set of size x. x<0 => link to ~x
int cols=4;
int[] setrows= new int[cols*2];
int islandCount = 0;
for (String s : matrix)
{
System.out.println(s);
//Make sure our rows are big enough
if (s.length() > cols)
{
cols=s.length();
if (setrows.length < cols*2)
{
int newlen = Math.max(cols,setrows.length)*2;
setrows = Arrays.copyOf(setrows, newlen);
}
}
//Create sets for land in bottom row, merging left
for (int col=0; col<s.length(); ++col)
{
if (!Character.isWhitespace(s.charAt(col)))
{
int idx = col*2+1;
setrows[idx]=1; //set of size 1
if (idx>=2 && setrows[idx-2]!=0)
{
union(setrows, idx, idx-2);
}
}
}
//merge up
for (int col=0; col<cols; ++col)
{
int topidx = col*2;
int botidx = topidx+1;
if (setrows[topidx]!=0 && setrows[botidx]!=0)
{
int toproot=find(setrows,topidx);
if ((toproot&1)!=0)
{
//top set is already linked down
union(setrows, toproot, botidx);
}
else
{
//link top root down. It does not matter that we aren't counting its size, since
//we will shortly throw it aaway
setrows[toproot] = ~botidx;
}
}
}
//count root sets, discard top row, and move bottom row up while fixing links
for (int col=0; col<cols; ++col)
{
int topidx = col * 2;
int botidx = topidx + 1;
if (setrows[topidx]>0)
{
++islandCount;
}
int v = setrows[botidx];
setrows[topidx] = (v>=0 ? v : v|1); //fix up link if necessary
setrows[botidx] = 0;
}
}
//count remaining root sets in top row
for (int col=0; col<cols; ++col)
{
if (setrows[col*2]>0)
{
++islandCount;
}
}
System.out.println("\nThere are "+islandCount+" islands there");
}
}
Here is the problem:
Given a string s and a non-empty string p, find all the start indices of p's anagrams in s.
Input: s: "cbaebabacd" p: "abc"
Output: [0, 6]
Input: s: "abab" p: "ab"
Output: [0, 1, 2]
Here is my solution
vector<int> findAnagrams(string s, string p) {
vector<int> res, s_map(26,0), p_map(26,0);
int s_len = s.size();
int p_len = p.size();
if (s_len < p_len) return res;
for (int i = 0; i < p_len; i++) {
++s_map[s[i] - 'a'];
++p_map[p[i] - 'a'];
}
if (s_map == p_map)
res.push_back(0);
for (int i = p_len; i < s_len; i++) {
++s_map[s[i] - 'a'];
--s_map[s[i - p_len] - 'a'];
if (s_map == p_map)
res.push_back(i - p_len + 1);
}
return res;
}
However, I think it is O(n^2) solution because I have to compare vectors s_map and p_map.
Does a O(n) solution exist for this problem?
lets say p has size n.
lets say you have an array A of size 26 that is filled with the number of a,b,c,... which p contains.
then you create a new array B of size 26 filled with 0.
lets call the given (big) string s.
first of all you initialize B with the number of a,b,c,... in the first n chars of s.
then you iterate through each word of size n in s always updating B to fit this n-sized word.
always B matches A you will have an index where we have an anagram.
to change B from one n-sized word to another, notice you just have to remove in B the first char of the previous word and add the new char of the next word.
Look at the example:
Input
s: "cbaebabacd"
p: "abc" n = 3 (size of p)
A = {1, 1, 1, 0, 0, 0, ... } // p contains just 1a, 1b and 1c.
B = {1, 1, 1, 0, 0, 0, ... } // initially, the first n-sized word contains this.
compare(A,B)
for i = n; i < size of s; i++ {
B[ s[i-n] ]--;
B[ s[ i ] ]++;
compare(A,B)
}
and suppose that compare(A,B) prints the index always A matches B.
the total complexity will be:
first fill of A = O(size of p)
first fill of B = O(size of s)
first comparison = O(26)
for-loop = |s| * (2 + O(26)) = |s| * O(28) = O(28|s|) = O(size of s)
____________________________________________________________________
2 * O(size of s) + O(size of p) + O(26)
which is linear in size of s.
Your solution is the O(n) solution. The size of the s_map and p_map vectors is a constant (26) that doesn't depend on n. So the comparison between s_map and p_map takes a constant amount of time regardless of how big n is.
Your solution takes about 26 * n integer comparisons to complete, which is O(n).
// In papers on string searching algorithms, the alphabet is often
// called Sigma, and it is often not considered a constant. Your
// algorthm works in (Sigma * n) time, where n is the length of the
// longer string. Below is an algorithm that works in O(n) time even
// when Sigma is too large to make an array of size Sigma, as long as
// values from Sigma are a constant number of "machine words".
// This solution works in O(n) time "with high probability", meaning
// that for all c > 2 the probability that the algorithm takes more
// than c*n time is 1-o(n^-c). This is a looser bound than O(n)
// worst-cast because it uses hash tables, which depend on randomness.
#include <functional>
#include <iostream>
#include <type_traits>
#include <vector>
#include <unordered_map>
#include <vector>
using namespace std;
// Finding a needle in a haystack. This works for any iterable type
// whose members can be stored as keys of an unordered_map.
template <typename T>
vector<size_t> AnagramLocations(const T& needle, const T& haystack) {
// Think of a contiguous region of an ordered container as
// representing a function f with the domain being the type of item
// stored in the container and the codomain being the natural
// numbers. We say that f(x) = n when there are n x's in the
// contiguous region.
//
// Then two contiguous regions are anagrams when they have the same
// function. We can track how close they are to being anagrams by
// subtracting one function from the other, pointwise. When that
// difference is uniformly 0, then the regions are anagrams.
unordered_map<remove_const_t<remove_reference_t<decltype(*needle.begin())>>,
intmax_t> difference;
// As we iterate through the haystack, we track the lead (part
// closest to the end) and lag (part closest to the beginning) of a
// contiguous region in the haystack. When we move the region
// forward by one, one part of the function f is increased by +1 and
// one part is decreased by -1, so the same is true of difference.
auto lag = haystack.begin(), lead = haystack.begin();
// To compare difference to the uniformly-zero function in O(1)
// time, we make sure it does not contain any points that map to
// 0. The the property of being uniformly zero is the same as the
// property of having an empty difference.
const auto find = [&](const auto& x) {
difference[x]++;
if (0 == difference[x]) difference.erase(x);
};
const auto lose = [&](const auto& x) {
difference[x]--;
if (0 == difference[x]) difference.erase(x);
};
vector<size_t> result;
// First we initialize the difference with the first needle.size()
// items from both needle and haystack.
for (const auto& x : needle) {
lose(x);
find(*lead);
++lead;
if (lead == haystack.end()) return result;
}
size_t i = 0;
if (difference.empty()) result.push_back(i++);
// Now we iterate through the haystack with lead, lag, and i (the
// position of lag) updating difference in O(1) time at each spot.
for (; lead != haystack.end(); ++lead, ++lag, ++i) {
find(*lead);
lose(*lag);
if (difference.empty()) result.push_back(i);
}
return result;
}
int main() {
string needle, haystack;
cin >> needle >> haystack;
const auto result = AnagramLocations(needle, haystack);
for (auto x : result) cout << x << ' ';
}
import java.util.*;
public class FindAllAnagramsInAString_438{
public static void main(String[] args){
String s="abab";
String p="ab";
// String s="cbaebabacd";
// String p="abc";
System.out.println(findAnagrams(s,p));
}
public static List<Integer> findAnagrams(String s, String p) {
int i=0;
int j=p.length();
List<Integer> list=new ArrayList<>();
while(j<=s.length()){
//System.out.println("Substring >>"+s.substring(i,j));
if(isAnamgram(s.substring(i,j),p)){
list.add(i);
}
i++;
j++;
}
return list;
}
public static boolean isAnamgram(String s,String p){
HashMap<Character,Integer> map=new HashMap<>();
if(s.length()!=p.length()) return false;
for(int i=0;i<s.length();i++){
char chs=s.charAt(i);
char chp=p.charAt(i);
map.put(chs,map.getOrDefault(chs,0)+1);
map.put(chp,map.getOrDefault(chp,0)-1);
}
for(int val:map.values()){
if(val!=0) return false;
}
return true;
}
}
I'm doing online course and got stuck at this problem.
The first line contains two non-negative integers 1 ≤ n, m ≤ 50000 — the number of segments and points on a line, respectively. The next n lines contain two integers a_i ≤ b_i defining the i-th segment. The next line contain m integers defining points. All the integers are of absolute value at most 10^8. For each segment, output the number of points it is used from the n-points table.
My solution is :
for point in points:
occurrence = 0
for l, r in segments:
if l <= point <= r:
occurrence += 1
print(occurrence),
The complexity of this algorithm is O(m*n), which is obviously not very efficient. What is the best way of solving this problem? Any help will be appreciated!
Sample Input:
2 3
0 5
7 10
1 6 11
Sample Output:
1 0 0
Sample Input 2:
1 3
-10 10
-100 100 0
Sample Output 2:
0 0 1
You can use sweep line algorithm to solve this problem.
First, break each segment into two points, open and close points.
Add all these points together with those m points, and sort them based on their locations.
Iterating through the list of points, maintaining a counter, every time you encounter an open point, increase the counter, and if you encounter an end point, decrease it. If you encounter a point in list m point, the result for this point is the value of counter at this moment.
For example 2, we have:
1 3
-10 10
-100 100 0
After sorting, what we have is:
-100 -10 0 10 100
At point -100, we have `counter = 0`
At point -10, this is open point, we increase `counter = 1`
At point 0, so result is 1
At point 10, this is close point, we decrease `counter = 0`
At point 100, result is 0
So, result for point -100 is 0, point 100 is 0 and point 0 is 1 as expected.
Time complexity is O((n + m) log (n + m)).
[Original answer] by how many segments is each point used
I am not sure I got the problem correctly but looks like simple example of Histogram use ...
create counter array (one item per point)
set it to zero
process the last line incrementing each used point counter O(m)
write the answer by reading histogram O(n)
So the result should be O(m+n) something like (C++):
const int n=2,m=3;
const int p[n][2]={ {0,5},{7,10} };
const int s[m]={1,6,11};
int i,cnt[n];
for (i=0;i<n;i++) cnt[i]=0;
for (i=0;i<m;i++) if ((s[i]>=0)&&(s[i]<n)) cnt[s[i]]++;
for (i=0;i<n;i++) cout << cnt[i] << " "; // result: 0 1
But as you can see the p[] coordinates are never used so either I missed something in your problem description or you missing something or it is there just to trick solvers ...
[edit1] after clearing the inconsistencies in OP the result is a bit different
By how many points is each segment used:
create counter array (one item per segment)
set it to zero
process the last line incrementing each used point counter O(m)
write the answer by reading histogram O(m)
So the result is O(m) something like (C++):
const int n=2,m=3;
const int p[n][2]={ {0,5},{7,10} };
const int s[m]={1,6,11};
int i,cnt[m];
for (i=0;i<m;i++) cnt[i]=0;
for (i=0;i<m;i++) if ((s[i]>=0)&&(s[i]<n)) cnt[i]++;
for (i=0;i<m;i++) cout << cnt[i] << " "; // result: 1,0,0
[Notes]
After added new sample set to OP it is clear now that:
indexes starts from 0
the problem is how many points from table p[n] are really used by each segment (m numbers in output)
Use Binary Search.
Sort the line segments according to 1st value and the second value. If you use c++, you can use custom sort like this:
sort(a,a+n,fun); //a is your array of pair<int,int>, coordinates representing line
bool fun(pair<int,int> a, pair<int,int> b){
if(a.first<b.first)
return true;
if(a.first>b.first)
return false;
return a.second < b.second;
}
Then, for every point, find the 1st line that captures the point and the first line that does not (after the line that does of course). If no line captures the point, you can return -1 or something (and not check for the point that does not).
Something like:
int checkFirstHold(pair<int,int> a[], int p,int min, int max){ //p is the point
while(min < max){
int mid = (min + max)/2;
if(a[mid].first <= p && a[mid].second>=p && a[mid-1].first<p && a[mid-1].second<p) //ie, p is in line a[mid] and not in line a[mid-1]
return mid;
if(a[mid].first <= p && a[mid].second>=p && a[mid-1].first<=p && a[mid-1].second>=p) //ie, p is both in line a[mid] and not in line a[mid-1]
max = mid-1;
if(a[mid].first < p && a[mid].second<p ) //ie, p is not in line a[mid]
min = mid + 1;
}
return -1; //implying no point holds the line
}
Similarly, write a checkLastHold function.
Then, find checkLastHold - checkFirstHold for every point, which is the answer.
The complexity of this solution will be O(n log m), as it takes (log m) for every calculation.
Here is my counter-based solution in Java.
Note that all points, segment start and segment end are read into one array.
If points of different PointType have the same x-coordinate, then the point is sorted after segment start and before segment end. This is done to count the point as "in" the segment if it coincides with both the segment start (counter already increased) and the segment end (counter not yet decreased).
For storing an answer in the same order as the points from the input, I create the array result of size pointsCount (only points counted, not the segments) and set its element with index SuperPoint.index, which stores the position of the point in the original input.
import java.util.Arrays;
import java.util.Scanner;
public final class PointsAndSegmentsSolution {
enum PointType { // in order of sort, so that the point will be counted on both segment start and end coordinates
SEGMENT_START,
POINT,
SEGMENT_END,
}
static class SuperPoint {
final PointType type;
final int x;
final int index; // -1 (actually does not matter) for segments, index for points
public SuperPoint(final PointType type, final int x) {
this(type, x, -1);
}
public SuperPoint(final PointType type, final int x, final int index) {
this.type = type;
this.x = x;
this.index = index;
}
}
private static int[] countSegments(final SuperPoint[] allPoints, final int pointsCount) {
Arrays.sort(allPoints, (o1, o2) -> {
if (o1.x < o2.x)
return -1;
if (o1.x > o2.x)
return 1;
return Integer.compare( o1.type.ordinal(), o2.type.ordinal() ); // points with the same X coordinate by order in PointType enum
});
final int[] result = new int[pointsCount];
int counter = 0;
for (final SuperPoint superPoint : allPoints) {
switch (superPoint.type) {
case SEGMENT_START:
counter++;
break;
case SEGMENT_END:
counter--;
break;
case POINT:
result[superPoint.index] = counter;
break;
default:
throw new IllegalArgumentException( String.format("Unknown SuperPoint type: %s", superPoint.type) );
}
}
return result;
}
public static void main(final String[] args) {
final Scanner scanner = new Scanner(System.in);
final int segmentsCount = scanner.nextInt();
final int pointsCount = scanner.nextInt();
final SuperPoint[] allPoints = new SuperPoint[(segmentsCount * 2) + pointsCount];
int allPointsIndex = 0;
for (int i = 0; i < segmentsCount; i++) {
final int start = scanner.nextInt();
final int end = scanner.nextInt();
allPoints[allPointsIndex] = new SuperPoint(PointType.SEGMENT_START, start);
allPointsIndex++;
allPoints[allPointsIndex] = new SuperPoint(PointType.SEGMENT_END, end);
allPointsIndex++;
}
for (int i = 0; i < pointsCount; i++) {
final int x = scanner.nextInt();
allPoints[allPointsIndex] = new SuperPoint(PointType.POINT, x, i);
allPointsIndex++;
}
final int[] pointsSegmentsCounts = countSegments(allPoints, pointsCount);
for (final int count : pointsSegmentsCounts) {
System.out.print(count + " ");
}
}
}
The title explains most of the question.
I have a tile grid which is represented by a 2D array. Some tiles are marked as empty (but they exist in the array, for certain continued uses) while others are in normal state.
What I need to do is, to reorder the remaining (non-empty) tiles in the grid so that all (or most) are in a different non-empty position. If I just iterate all the non-empty positions and swap the tile with another random one, I might be already reordering many of them automatically (the swapped ones).
So I was wondering if there's some technique I can follow so as to reorder the grid satisfactorily with minimal looping. Any hints?
public void RandomizeGrid<T>(T[,] grid, Func<T,bool> isEmpty)
{
// Create a list of the indices of all non-empty cells.
var indices = new List<Point>();
int width = grid.GetLength(0);
int height = grid.GetLength(1);
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
if (!isEmpty(grid[x,y])) // function to check emptiness
{
indices.Add(new Point(x,y));
}
}
}
// Randomize the cells using the index-array as displacement.
int n = indices.Count;
var rnd = new Random();
for (int i = 0; i < n; i++)
{
int j = rnd.Next(i,n); // Random index i <= j < n
if (i != j)
{
// Swap the two cells
var p1 = indices[i];
var p2 = indices[j];
var tmp = grid[p1.X,p1.Y];
grid[p1.X,p1.Y] = grid[p2.X,p2.Y];
grid[p2.X,p2.Y] = tmp;
}
}
}
Would it meet your needs ("satisfactorily" is a bit vague) to ensure that every non empty tile was swapped with one other non-empty tile one time?
Say you have a list :
(1,4,7,3,8,10)
we can write down the indicies of the list
(0,1,2,3,4,5)
and perform N random swaps on the indices to shuffle it - maybe some numbers move, some don't.
(5,1,3,2,4,0)
Then take these pairwise as a sequence of swaps to perform on our original list.
(8,10,3,7,1,4)
if you have an odd number of elements, the leftover is swapped with any other element in the list.