I thought this problem had a trivial solution, couple of for loops and some fancy counters, but apparently it is rather more complicated.
So my question is, how would you write (in C) a function traversal of a square matrix in diagonal strips.
Example:
1 2 3
4 5 6
7 8 9
Would have to be traversed in the following order:
[1],[2,4],[3,5,7],[6,8],[9]
Each strip above is enclosed by square brackets.
One of the requirements is being able to distinguish between strips. Meaning that you know when you're starting a new strip. This because there is another function that I must call for each item in a strip and then before the beginning of a new strip. Thus a solution without code duplication is ideal.
Here's something you can use. Just replace the printfs with what you actually want to do.
#include <stdio.h>
int main()
{
int x[3][3] = {1, 2, 3,
4, 5, 6,
7, 8, 9};
int n = 3;
for (int slice = 0; slice < 2 * n - 1; ++slice) {
printf("Slice %d: ", slice);
int z = (slice < n) ? 0 : slice - n + 1;
for (int j = z; j <= slice - z; ++j) {
printf("%d ", x[j][slice - j]);
}
printf("\n");
}
return 0;
}
Output:
Slice 0: 1
Slice 1: 2 4
Slice 2: 3 5 7
Slice 3: 6 8
Slice 4: 9
I would shift the rows like so:
1 2 3 x x
x 4 5 6 x
x x 7 8 9
And just iterate the columns. This can actually be done without physical shifting.
Let's take a look how matrix elements are indexed.
(0,0) (0,1) (0,2) (0,3) (0,4)
(1,0) (1,1) (1,2) (1,3) (1,4)
(2,0) (2,1) (2,2) (2,3) (2,4)
Now, let's take a look at the stripes:
Stripe 1: (0,0)
Stripe 2: (0,1) (1,0)
Stripe 3: (0,2) (1,1) (2,0)
Stripe 4: (0,3) (1,2) (2,1)
Stripe 5: (0,4) (1,3) (2,2)
Stripe 6: (1,4) (2,3)
Stripe 7: (2,4)
If you take a closer look, you'll notice one thing. The sum of indexes of each matrix element in each stripe is constant. So, here's the code that does this.
public static void printSecondaryDiagonalOrder(int[][] matrix) {
int rows = matrix.length;
int cols = matrix[0].length;
int maxSum = rows + cols - 2;
for (int sum = 0; sum <= maxSum; sum++) {
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
if (i + j - sum == 0) {
System.out.print(matrix[i][j] + "\t");
}
}
}
System.out.println();
}
}
It's not the fastest algorithm out there (does(rows * cols * (rows+cols-2)) operations), but the logic behind it is quite simple.
I found this here: Traverse Rectangular Matrix in Diagonal strips
#include <stdio.h>
int main()
{
int x[3][4] = { 1, 2, 3, 4,
5, 6, 7, 8,
9, 10, 11, 12};
int m = 3;
int n = 4;
for (int slice = 0; slice < m + n - 1; ++slice) {
printf("Slice %d: ", slice);
int z1 = slice < n ? 0 : slice - n + 1;
int z2 = slice < m ? 0 : slice - m + 1;
for (int j = slice - z2; j >= z1; --j) {
printf("%d ", x[j][slice - j]);
}
printf("\n");
}
return 0;
}
output:
Slice 0: 1
Slice 1: 5 2
Slice 2: 9 6 3
Slice 3: 10 7 4
Slice 4: 11 8
Slice 5: 12
I found this a quite elegant way of doing it as it only needs memory for 2 additonal variables (z1 and z2), which basically hold the information about the length of each slice. The outer loop moves through the slice numbers (slice) and the inner loop then moves through each slice with index: slice - z1 - z2. All other information you need then where the algorithm starts and how it moves through the matrix. In the preceding example it will move down the matrix first, and after it reaches the bottom it will move right: (0,0) -> (1,0) -> (2,0) -> (2,1) -> (2,2) -> (2,3). Again this pattern is captured by the varibales z1 and z2. The row increments together with the slice number untill it reaches the bottom, then z2 will start to increment which can be used to keep the row index constant at it's position: slice - z2. Each slice's length is known by: slice - z1 - z2, perofrming the following: (slice - z2) - (slice - z1 -z2) (minus as the algorithm moves in ascending order m--, n++) results in z1 which is the stopping criterium for the inner loop. Only the column index remains which is conveniently inherited from the fact that j is constant after it reaches the bottom, after which the column index starts to increment.
Preceding algorithm moves only in ascending order from left to right starting at the top left (0,0). When I needed this algorithm I also needed to search through a matrix in descending order starting at the bottom left (m,n). Because I was quite smitten by the algorithm I decided to get to the bottom and adapt it:
slice length is again known by: slice -z1 - z2
The starting position of the slices are: (2,0) -> (1,0) -> (0,0) -> (0,1) -> (0,2) -> (0,3)
The movement of each slice is m++ and n++
I found it quite usefull to depict it as follows:
slice=0 z1=0 z2=0 (2,0) (column index= rowindex - 2)
slice=1 z1=0 z2=0 (1,0) (2,1) (column index= rowindex - 1)
slice=2 z1=0 z2=0 (0,0) (1,1) (2,2) (column index= rowindex + 0)
slice=3 z1=0 z2=1 (0,1) (1,2) (2,3) (column index= rowindex + 1)
slice=4 z1=1 z2=2 (0,2) (1,3) (column index= rowindex + 2)
slice=5 z1=2 z2=3 (0,3) (column index= rowindex + 3)
Deriving the following: j = (m-1) - slice + z2 (with j++)
using the expression of the slice length to make the stopping criterium:((m-1) - slice + z2)+(slice -z2 - z1) results into: (m-1) - z1
We now have the argumets for the innerloop: for (int j = (m-1) - slice + z2; j < (m-1) - z1; j++)
The row index is know by j, and again we know that the column index only starts incrementing when j starts being constant, and thus having j in the expression again is not a bad idea. From the differences between the above summation I noticed that the difference is always equal to j - (slice - m +1), testing this for some other cases I was confident that this would hold for all cases (I'm not a mathematician ;P) and thus the algorithm for descending movement starting from the bottom left looks as follows:
#include <stdio.h>
int main()
{
int x[3][4] = { 1, 2, 3, 4,
5, 6, 7, 8,
9, 10, 11, 12};
int m = 3;
int n = 4;
for (int slice = 0; slice < m + n - 1; ++slice) {
printf("Slice %d: ", slice);
int z1 = slice < n ? 0 : slice - n + 1;
int z2 = slice < m ? 0 : slice - m + 1;
for (int j = (m-1) - slice + z2; j <= (m-1) - z1; j++) {
printf("%d ", x[j][j+(slice-m+1)]);
}
printf("\n");
}
return 0;
}
Now I leave the other two directions up to you ^^ (which is only important when the order is actually important).
This algorithm is quite a mind bender, even when you think you know how it works it can still bite you in the ass. However I think it is quite beautifull because it literally moves through the matrix as you would expect. I am interested if anyone knows more about the algorithm, a name for instance, so I can look if what I have done here actually makes sense and maybe there is a better solutions.
I think this can be a solution for any type of matrix.
#include <stdio.h>
#define M 3
#define N 4
main(){
int a[M][N] = {{1, 2, 3, 4},
{5, 6, 7, 8},
{9,10,11,12}};
int i, j, t;
for( t = 0; t<M+N; ++t)
for( i=t, j=0; i>=0 ; --i, ++j)
if( (i<M) && (j<N) )
printf("%d ", a[i][j]);
return 0;
}
I thought this problem had a trivial solution, couple of for loops and some fancy counters
Precisely.
The important thing to notice is that if you give each item an index (i, j) then items on the same diagonal have the same value j+n–i, where n is the width of your matrix. So if you iterate over the matrix in the usual way (i.e. nested loops over i and j) then you can keep track of the diagonals in an array that is addressed in the above mentioned way.
// This algorithm works for matrices of all sizes. ;)
int x = 0;
int y = 0;
int sub_x;
int sub_y;
while (true) {
sub_x = x;
sub_y = y;
while (sub_x >= 0 && sub_y < y_axis.size()) {
this.print(sub_x, sub_y);
sub_x--;
sub_y++;
}
if (x < x_axis.size() - 1) {
x++;
} else if (y < y_axis.size() - 1) {
y++;
} else {
break;
}
}
The key is to iterate every item in the first row, and from it go down the diagonal. Then iterate every item in the last column (without the first, which we stepped through in the previous step) and then go down its diagonal.
Here is source code that assumes the matrix is a square matrix (untested, translated from working python code):
#define N 10
void diag_step(int[][] matrix) {
for (int i = 0; i < N; i++) {
int j = 0;
int k = i;
printf("starting a strip\n");
while (j < N && i >= 0) {
printf("%d ", matrix[j][k]);
k--;
j++;
}
printf("\n");
}
for (int i = 1; i < N; i++) {
int j = N-1;
int k = i;
printf("starting a strip\n");
while (j >= 0 && k < N) {
printf("%d ", matrix[k][j]);
k++;
j--;
}
printf("\n");
}
}
Pseudo code:
N = 2 // or whatever the size of the [square] matrix
for x = 0 to N
strip = []
y = 0
repeat
strip.add(Matrix(x,y))
x -= 1
y -= 1
until x < 0
// here to print the strip or do some' with it
// And yes, Oops, I had missed it...
// the 2nd half of the matrix...
for y = 1 to N // Yes, start at 1 not 0, since main diagonal is done.
strip = []
x = N
repeat
strip.add(Matrix(x,y))
x -= 1
y += 1
until x < 0
// here to print the strip or do some' with it
(Assumes x indexes rows, y indexes columns, reverse these two if matrix is indexed the other way around)
Just in case somebody needs to do this in python, it is very easy using numpy:
#M is a square numpy array
for i in range(-M.shape[0]+1, M.shape[0]):
print M.diagonal(offset=i)
public void printMatrix(int[][] matrix) {
int m = matrix.length, n = matrix[0].length;
for (int i = 0; i < m + n - 1; i++) {
int start_row = i < m ? i : m - 1;
int start_col = i < m ? 0 : i - m + 1;
while (start_row >= 0 && start_col < n) {
System.out.print(matrix[start_row--][start_col++]);
}
System.out.println("\n")
}
}
you have to break the matrix in to upper and lower parts, and iterate each of them separately, one half row first, another column first.
let us assume the matrix is n*n, stored in a vector, row first, zero base, loops are exclusive to last element.
for i in 0:n
for j in 0:i +1
A[i + j*(n-2)]
the other half can be done in a similar way, starting with:
for j in 1:n
for i in 0:n-j
... each step is i*(n-2) ...
I would probably do something like this (apologies in advance for any index errors, haven't debugged this):
// Operation to be performed on each slice:
void doSomething(const int lengthOfSlice,
elementType *slice,
const int stride) {
for (int i=0; i<lengthOfSlice; ++i) {
elementType element = slice[i*stride];
// Operate on element ...
}
}
void operateOnSlices(const int n, elementType *A) {
// distance between consecutive elements of a slice in memory:
const int stride = n - 1;
// Operate on slices that begin with entries in the top row of the matrix
for (int column = 0; column < n; ++column)
doSomething(column + 1, &A[column], stride);
// Operate on slices that begin with entries in the right column of the matrix
for (int row = 1; row < n; ++row)
doSomething(n - row, &A[n*row + (n-1)], stride);
}
static int[][] arr = {{ 1, 2, 3, 4},
{ 5, 6, 7, 8},
{ 9,10,11,12},
{13,14,15,16} };
public static void main(String[] args) {
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j < i+1; j++) {
System.out.print(arr[j][i-j]);
System.out.print(",");
}
System.out.println();
}
for (int i = 1; i < arr.length; i++) {
for (int j = 0; j < arr.length-i; j++) {
System.out.print(arr[i+j][arr.length-j-1]);
System.out.print(",");
}
System.out.println();
}
}
A much easier implementation:
//Assuming arr as ur array and numRows and numCols as what they say.
int arr[numRows][numCols];
for(int i=0;i<numCols;i++) {
printf("Slice %d:",i);
for(int j=0,k=i; j<numRows && k>=0; j++,k--)
printf("%d\t",arr[j][k]);
}
#include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
int N = 0;
cin >> N;
vector<vector<int>> m(N, vector<int>(N, 0));
for (int i = 0; i < N; ++i)
{
for (int j = 0; j < N; ++j)
{
cin >> m[i][j];
}
}
for (int i = 1; i < N << 1; ++i)
{
for (int j = 0; j < i; ++j)
{
if (j < N && i - j - 1 < N)
{
cout << m[j][i - j - 1];
}
}
cout << endl;
}
return 0;
}
A simple python solution
from collections import defaultdict
def getDiagonals(matrix):
n, m = len(matrix), len(matrix[0])
diagonals = defaultdict(list)
for i in range(n):
for j in range(m):
diagonals[i+j].append(matrix[i][j])
return list(diagonals.values())
matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
assert getDiagonals(matrix) == [[1], [2, 4], [3, 5, 7], [6, 8], [9]]
Related
The code below should have counted the number of triangles that can be formed out of every triplet of 3 distinct integers from the given range 1...N. However, when I input 5, it gives me 34, while the right answer is 3: the only possible triangles are (2, 3, 4), (2, 4, 5) and (3, 4, 5).
// C code to count the number of possible triangles using
#include <stdio.h>
int main()
{ int N, count=0;
setvbuf(stdout, NULL, _IONBF, 0);
printf("Please input the value of N: \n");
scanf("%d", &N );
for (int i = 1; i < N; i++) {
for (int j = 1; j < N; j++) {
// The innermost loop checks for the triangle
// property
for (int k = 1; k < N; k++) {
// Sum of two sides is greater than the
// third
if (i + j > k && i + k > j && k + j > i)
{
count++;
}
}
}
}
printf ("Total number of triangles possible is %d ",count);
return 0;
}
You do not ensure that the numbers are distinct.
You can do this be chosing your loop limits correctly:
for (int i = 1; i <= N-2; i++) {
for (int j = i+1; j <= N-1; j++) {
for (int k = j+1; k <= N; k++) {
Start each inner loop one higher than current counter of outer loop. It also does not make any sense to run each loop up to N. If they must be distinct, you can stop at N-2, N-1, N
This creates triples where numbers are increasing.
If you consider triangles (3,4,5) and (4,3,5) to be different, we must also account for permuations of these triples.
As all values are distinct, we have 6 possible permutations for each triple that was found in the inner loop.
I'm sorry, I can't go for a comment so let's go for an answer.
I don't really get what you wish to do. As I am understanding it, you wish to print this :
1, 2, 3, 4, 5-> [2, 3, 4], [2, 4, 5], [3, 4, 5] -> 3
Except, with your code, you'll never check your N since you go out of your loop when i turns into N.
Also, your "j" and "k" don't have to move starting 1 since you already tried that position with "i", so you'll only get doublons doing that.
EDIT : some changes for a smarter code (I removed my +1 but go check for "<=", which I personnaly dislike :) ):
// since [1, 2, 3] can't bring any triangle
if (N < 4) return 0;
// since there is no possible triangle with 1 as a border, start at 2
for (int i = 2; i <= N-2; i++) {
for (int j = i+1; j <= N-1; j++) {
// The innermost loop checks for the triangle
// property
for (int k = j+1; k <= N; k++) {
// Sum of two sides is greater than the
// third
// simplified as suggested by S M Samnoon Abrar
if (i + j > k)
{
count++;
}
}
}
You need to do the following:
run first loop through 1 to N, i.e.: 1 <= i <= N
don't start each nested loop from index 1. So, you need to run first nested loop in range i+1 <= j <= N and second nested loop in range j+1 <= k <=N.
Explanation
First, if you run all 3 loops from 1 to N, then you are not doing distinct counting because all numbers in the range will be iterated 3 times. So it would give an incorrect result.
Secondly, since we need to count distinct numbers only, it is efficient to count +1 from the previous outer loop each time. In this way, we are ensuring that we are not iterating over any number twice.
Check the following code:
// C code to count the number of possible triangles using
#include <stdio.h>
int main()
{ int N, count=0;
setvbuf(stdout, NULL, _IONBF, 0);
printf("Please input the value of N: \n");
scanf("%d", &N );
for (int i = 1; i <= N; i++) {
for (int j = i+1; j <= N; j++) {
// The innermost loop checks for the triangle
// property
for (int k = j+1; k <= N; k++) {
// Sum of two sides is greater than the
// third
if (i + j > k && i + k > j && k + j > i)
{
count++;
}
}
}
}
printf ("Total number of triangles possible is %d ",count);
return 0;
}
Spot the extra line of code that enforces the constraint that the 3 numbers are "distinct" (read "unique"). Funny what a little "print debugging" can turn up...
printf("Please input the value of N: ");
scanf("%d", &N );
for (int i = 1; i < N; i++) {
for (int j = 1; j < N; j++) {
for (int k = 1; k < N; k++) {
if (i + j > k && i + k > j && k + j > i) {
if( i != j && j != k && k != i ) {
printf( "%d %d %d\n", i, j, k );
count++;
}
}
}
}
}
printf ("Total number of triangles possible is %d ",count);
Output
Please input the value of N: 5
2 3 4
2 4 3
3 2 4
3 4 2
4 2 3
4 3 2
Total number of triangles possible is 6
The OP code was counting (1,1,1) or (2,3,3) in contravention of "distinct" digits.
AND, there is now ambiguity from the OP person as to whether, for instance, (4,2,3) and (4,3,2) are distinct.
printf() - the coder's friend when things don't make sense...
I'm trying to implement insertion sort but I don't seem to be able to correctly swap the values into their right place.
Here's what I have so far:
void insertion(int ar[], int n) {
for (int i = 1; i < n; i++) {
int temp = ar[i];
int j = i;
while (ar[j - 1] > ar[i] && (j - 1) >= 0) {
ar[i] = ar[j - 1];
ar[j - 1] = temp;
}
}
}
This source summarizes the steps of the insertion-sort algorithm as follows:
Algorithm : To sort an array of size n in ascending order:
1: Iterate from arr[1] to arr[n] over the array.
2: Compare the current element (key) to its predecessor.
3: If the key element is smaller than its predecessor, compare it to the elements before. Move the greater elements one position up to make space for the swapped element.
The first step you got it right:
void insertion(int ar[], int n) {
for (int i = 1; i < n; i++) {
// ..
}
}
however you completely miss the second step, and your while loop:
int j = i;
while (ar[j - 1] > ar[i] && (j - 1) >= 0) {
ar[i] = ar[j - 1];
ar[j - 1] = temp;
}
has some issues, namely 1) it is stuck in an infinite loop because the variable j is never decremented; 2) its conditionals should be swapped, so instead of ar[j - 1] > ar[i] && (j - 1) >= 0 it should be (j - 1) >= 0 && ar[j - 1] > ar[i]. Otherwise, you would be accessing the position -1 of the array ar
SPOILER
A possible implementation of the insertion sort could look like:
void insertionSort(int arr[], int n)
{
int j = 0;
for (int i = 1; i < n; i++) {
int key = arr[i];
for (j = i - 1; j >= 0 && arr[j] > key;) {
arr[j + 1] = arr[j];
j = j - 1;
}
arr[j + 1] = key;
}
}
Lets us see how it works with the input [8, 6, 4, 20, 10] (the key is represented by '()')
i = 1, j = 0, key = 6; In the inner loop [<8>, (6), 4, 20, 10]; 6 < 8 true arr[j + 1] = arr[j]; which leads to [<8>, (8), 4, 20, 10]. j = -1, the inner loop stops and arr[j + 1] = key; turns the array into [(6), 8, 4, 20, 10].
At this point, we know that the smallest element is in the first position. Therefore, we do not have to consider it in the next iterations
[6, <8>, (4), 20, 10]; 4 < 8 true so let's move 4 before 6; -> [(4), 6, 8, 20, 10];
At this point, we know that the two smallest elements are in the first two positions. Therefore, we do not have to consider them in the next iterations
[4, 6, <8>, (20), 10]; 20 < 8 false so let's move on;
At this point, we know that the three smallest elements are in the first three positions. Therefore, we do not have to consider them in the next iterations
[4, 6, 8, <20>, (10)]; 10 < 20 true so let us move 20 before 10 -> [4, 6, 8, (10), 20];
At this point, we know that the four smallest elements are in the first four positions. Therefore, we do not have to consider them in the next iterations
i < n is false, we exit the outer loop and the array is sorted.
Given an array of 3 elements :- 2,4,5
and given a number n = 10
Find count of all numbers in the range 1 to n which are not dvisible by multiple of all array elements.
output:- 4
(1,3,7,9)
Any better approach brute force?
n is in the range of 1 to 10^9
take a hashset and put all multiples of the arrayElements lesser than n and subtract the set size.
int n = 10;
int k = 3;
int[] jump = { 2, 5, 4 };
Set<Integer> jumpSet = new HashSet<Integer>();
for (int i = 0; i < jump.length; i++) {
if (!jumpSet.contains(jump[i])) {
for (int j = 1; j <= n / jump[i]; j++)
jumpSet.add(jump[i] * j);
}
}
System.out.println(n - jumpSet.size());
I need to implement a pretty easy in-place LU-decomposition of matrix A. I'm using Gaussian elimination and I want to test it with a 3x3 matrix. The problem is, I keep getting stack smashing error and I don't have any idea why. I don't see any problems in my code, which could do this. Do you have any idea?
The problem is probably in the Factorization block.
###My code:###
#include <stdio.h>
int main() {
int n = 3; // matrix size
int A[3][3] = {
{1, 4, 7},
{2, 5, 8},
{3, 6, 10}
};
printf("Matrix A:\n");
for( int i=0; i < n; i++ ) {
for( int j=0; j < n; j++ ) {
printf("%d ", A[i][j]);
if ( j % 2 == 0 && j != 0 ) {
printf("\n");
}
}
}
// FACTORIZATION
int k;
int rows;
for( k = 0; k < n; k++ ) {
rows = k + k+1;
A[rows][k] = A[rows][k]/A[k][k];
A[rows][rows] = A[rows][rows] - A[rows][k] * A[k][rows];
printf("k: %d\n", k);
}
printf("Matrix after decomp:\n");
for( int i=0; i < n; i++ ) {
for( int j=0; j < n; j++ ) {
printf("%d ", A[i][j]);
if ( j % 3 == 0 && j != 0 ) {
printf("\n");
}
}
}
return 0;
}
Your error is most likely here:
rows = k + k+1;
A[rows][k] = A[rows][k]/A[k][k];
A[rows][rows] = A[rows][rows] - A[rows][k] * A[k][rows];
This means that rows goes through the values 1, 3, 5; and is then used to access an array with only three elements. That would, indeed, overflow, as the only valid offset among those is 1.
EDIT: Looking at your Matlab code, it is doing something completely different, as rows = k + 1:n sets rows to a small vector, which it then uses the splice the matrix, something C does not support as a primitive. You would need to reimplement both that and the matrix multiplication A(rows, k) * A(k, rows) using explicit loops.
Your original Matlab code was (Matlab has 1-based indexing):
for k = 1:n - 1
rows = k + 1:n
A(rows, k) = A(rows, k) / A(k, k)
A(rows, rows) = A(rows, rows) - A(rows, k) * A(k, rows)
end
What rows = k + 1:n this does is that it sets rows to represent a range. The expression A(rows, k) is actually a reference to a vector-shaped slice of the matrix, and Matlab can divide a vector by a scalar.
On the last line, A(rows, rows) is a matrix-shaped slice , and A(rows, k) * A(k, rows) is a matrix multiplication, e.g. multiplying matrices of dimension (1,3) and (3,1) to get one of (3,3).
In C you can't do that using the builtin = and / operators.
The C equivalent is:
for ( int k = 0; k < n - 1; ++k )
{
// A(rows, k) = A(rows, k) / A(k, k)
for ( int row = k + 1; row < n; ++row )
A[row][k] /= A[k][k];
// A(rows, rows) = A(rows, rows) - A(rows, k) * A(k, rows)
for ( int row = k + 1; row < n; ++row )
for ( int col = k + 1; col < n; ++col )
A[row][col] -= A[row][k] * A[k][col];
}
(disclaimer: untested!)
The first part is straightforward: every value in a vector is being divided by a scalar.
However, the second line is more complicated. The Matlab code includes a matrix multiplication and a matrix subtraction ; and also the operation of extracting a sub-matrix from a matrix. If we tried to write a direct translation of that to C, it is very complicated.
We need to use two nested loops to iterate over the rows and columns to perform this operation on the square matrix.
I encountred this function without any comment. I wonder what is this function doing? Any help?
int flr(int n, char a[])
{
#define A(i) a[((i) + k) % n]
int l[n], ls = n, z[n], min = 0;
for (int i = 0; i < n; i++)
{
l[i] = i;
z[i] = 1;
}
for (int k = 0; ls >= 2; k++)
{
min = l[0];
for (int i=0; i<ls; i++) min = A(l[i])<A(min) ? l[i] : min;
for (int i=0; i<ls; i++) z[A(l[i])!=A(min) ? l[i] : (l[i]+k+1)%n] = 0;
for (int ls_=ls, i=ls=0; i<ls_; i++) if (z[l[i]]) l[ls++] = l[i];
}
return ls == 1 ? l[0] : min;
}
What a fun problem!
Other posters are correct that it returns the index of a minimum, but it's actually more interesting than that.
If you treat the array as being circular (i.e. when you get past the end, go back to the beginning), the function returns the starting index of the minimum lexicographic subsequence.
If only one element is minimal, that element is returned. If multiple elements are minimal, we compare the next element along from each minimal element.
E.g. with an input of 10 and {0, 1, 2, 1, 1, 1, 0, 0, 1, 0}:
There are four minimal elements of 0, at indices 0, 6, 7 and 9
Of these two are followed by a 1 (the 0 and 7 elements), and two are followed by a 0 (the 6 and 9 elements). Remember that the array is circular.
0 is smaller than 1, so we only consider the 0s at 6 and 9.
Of these the sequence of 3 elements starting at 6 is '001' and the sequence from 9 is also '001', so they're still both equally minimal
Looking at the sequence of 4 elements, we have '0010' from element 6 onwards and '0012' from element 9 onwards. The sequence from 6 onwards is therefore smaller and 6 is returned. (I've checked that this is the case).
Refactored and commented code follows:
int findStartOfMinimumSubsequence(int length, char circular_array[])
{
#define AccessWithOffset(index) circular_array[(index + offset) % length]
int indicesStillConsidered[length], count_left = length, indicator[length], minIndex = 0;
for (int index = 0; index < length; index++)
{
indicesStillConsidered[index] = index;
indicator[index] = 1;
}
// Keep increasing the offset between pairs of minima, until we have eliminated all of
// them or only have one left.
for (int offset = 0; count_left >= 2; offset++)
{
// Find the index of the minimal value for the next term in the sequence,
// starting at each of the starting indicesStillConsidered
minIndex = indicesStillConsidered[0];
for (int i=0; i<count_left; i++)
minIndex = AccessWithOffset(indicesStillConsidered[i])<AccessWithOffset(minIndex) ?
indicesStillConsidered[i] :
minIndex;
// Ensure that indicator is 0 for indices that have a non-minimal next in sequence
// For minimal indicesStillConsidered[i], we make indicator 0 1+offset away from the index.
// This prevents a subsequence of the current sequence being considered, which is just an efficiency saving.
for (int i=0; i<count_left; i++){
offsetIndexToSet = AccessWithOffset(indicesStillConsidered[i])!=AccessWithOffset(minIndex) ?
indicesStillConsidered[i] :
(indicesStillConsidered[i]+offset+1)%length;
indicator[offsetIndexToSet] = 0;
}
// Copy the indices where indicator is true down to the start of the l array.
// Indicator being true means the index is a minimum and hasn't yet been eliminated.
for (int count_before=count_left, i=count_left=0; i<count_before; i++)
if (indicator[indicesStillConsidered[i]])
indicesStillConsidered[count_left++] = indicesStillConsidered[i];
}
return count_left == 1 ? indicesStillConsidered[0] : minIndex;
}
Sample uses
Hard to say, really. Contrived example: from a circular list of letters, this would return the index of the shortest subsequence that appears earlier in a dictionary than any other subsequence of the same length (assuming all the letters are lower case).
It returns the position of the smallest element within the substring of a ranging from element 0..n-1.
Test code
#include <stdio.h>
int flr(int n, char a[])
{
#define A(i) a[((i) + k) % n]
int l[n], ls = n, z[n], min = 0;
for (int i = 0; i < n; i++)
{
l[i] = i;
z[i] = 1;
}
for (int k = 0; ls >= 2; k++)
{
min = l[0];
for (int i=0; i<ls; i++) min = A(l[i])<A(min) ? l[i] : min;
for (int i=0; i<ls; i++) z[A(l[i])!=A(min) ? l[i] : (l[i]+k+1)%n] = 0;
for (int ls_=ls, i=ls=0; i<ls_; i++) if (z[l[i]]) l[ls++] = l[i];
}
return ls == 1 ? l[0] : min;
}
int main() {
printf(" test 1: %d\n", flr(4, "abcd"));
printf(" test 3: %d\n", flr(6, "10e-10"));
printf(" test 3: %d\n", flr(3, "zxyghab");
printf(" test 4: %d\n", flr(5, "bcaaa"));
printf(" test 5: %d\n", flr(7, "abcd"));
return 0;
}
This code gives following output:
[root#s1 sf]# ./a.out
test 1: 0
test 2: 3
test 3: 1
test 4: 2
test 5: 4
1. 0 is the position of `a` in the first case
2. 3 is the position of `-` in second case.
3. 1 is the position of `x` in third case.
4. 2 is the position of the second `a`.
5. 4 is the position of the `\0`
So the function returns the position of smallest element of a character pointer pointed by a and it will consider n elements. (Thats why it returned the position of x in the third case).
But when multiple smallest element available, it does not seems to be work in a predictable way, as it does not return the first occurrence, nor the last.
It should do a error checking for out of bound cases. Which may lead to problem in future.
so i'm running tests on this.
int flr(int n, char a[])
{
#define A(i) a[((i) + k) % n]
int l[n], ls = n, z[n], min = 0;
for (int i = 0; i < n; i++)
{
l[i] = i;
z[i] = 1;
}
for (int k = 0; ls >= 2; k++)
{
min = l[0];
for (int i=0; i<ls; i++) min = A(l[i])<A(min) ? l[i] : min;
for (int i=0; i<ls; i++) z[A(l[i])!=A(min) ? l[i] : (l[i]+k+1)%n] = 0;
for (int ls_=ls, i=ls=0; i<ls_; i++) if (z[l[i]]) l[ls++] = l[i];
}
return ls == 1 ? l[0] : min;
}
int main()
{
int in = 10;
char array[] = {0, 1, 1, 1, 1, 1, 0, 1, 1, 0};
int res = flr(in, array);
printf("expecting res to be 6;\tres = %d\n", res);
system("pause");
return 0;
}
output was res=9;