We have an array of some length(say 3) and some counting sequence: 0,1,2,3,4,... to infinity. Out of that input sequence we need to produce sequence that will traverse through array back and forth, like that: 0,1,2,1,0,1,2,1,0,... and so on for a length=3.
I think this task is a very common one in a many programming books, but i was not able to find standard solution, so i created my own solution. Are there any other more efficient and elegant solution, because i dont like my solution???
#define LENGTH 5
int main()
{
char arr[LENGTH] = {'a','b','c','d','e'};
int i;
int base=0;
for(i=0;i<100;i++){
if(i%(LENGTH-1)==0){
if(base==0) base=LENGTH-1;
else base =0;
}
int j = abs(base-i%(LENGTH-1));
printf("%c ",arr[j]);
}
}
Java code (for your convenience):
public static void traverse(){
char arr[] = {'a','b','c','d','e'};
int base=0;
for(int i=0;i<100;i++){
if(i%(arr.length-1)==0){
if(base==0) base=arr.length-1;
else base =0;
}
int j = Math.abs(base-i%(arr.length-1));
System.out.println(arr[j]+" ");
}
}
This solution calculates the index of arr only from i, thus avoiding the need to keep any state (such as current direction). As a result it is a bit more convoluted, but would also work for non-consecutive values of i.
char arr[] = { '0', '1', '2', '3', '4' };
const int LENGTH = sizeof arr / sizeof(*arr); // not necessary for char
assert(LENGTH > 1); // doesn't work for fewer than 2 elements
const int CYCLE = LENGTH - 1;
for (int i = 0; i < 100; ++i) {
printf("%c ", arr[ (i / CYCLE) & 1 ? CYCLE - i % CYCLE : i % CYCLE ]);
}
printf("\n");
Explanation: i / CYCLE is the number of the cycle through the array, and & 1 checks the least significant bit of that number to determine the direction (odd cycles where the bit is 1 go backwards, even cycles – starting from 0 – go forwards). i % CYCLE is the forwards cycle, but since CYCLE = LENGTH - 1, it doesn't reach the last index of the array. CYCLE - i % CYCLE is the backwards cycle, starting from CYCLE - 0, which is the last index that wasn't reached when going forwards, and ending at 1, thus avoiding repetition of index 0 when going forwards again.
In other words, both the forwards and the backwards cycles omit one index to avoid repetition when changing direction, hence CYCLE = LENGTH - 1, which also means that LENGTH must be at least 2 to avoid division by zero.
Maybe something like this:
#define LENGTH 5
int main()
{
char arr[LENGTH] = { 'a','b','c','d','e' };
int current = 0;
int direction = 1;
for (int i = 0; i < 100; i++)
{
printf("%c ", arr[current]);
if (current == 0)
direction = 1;
else if (current == LENGTH - 1)
direction = -1;
current += direction;
}
}
Related
I'm a student and I'm taking a DSA course. On our latest assignment we were asked to implement a recursive variation of bubble sort. The assignment was alrady submitted but I couldn't make it work and it's frustrating me. I've triple checked everything and I can't find the problem.
The general pseudo-code for the algorithm is:
if (n > 10) // n being the size of array A
sort recursivley the first 2/3 elements in A (from 0 to ceil(2n/3))
sort recursivley the last 2/3 elements in A (from floor(n/3) to n)
sort recursivley the first 2/3 elements in A (from 0 to ceil(2n/3))
else
use bubbleSort
This is the code I wrote:
public static void weirdSort(double[] arr, int start, int end, int size) {
if (size > 10) {
int weirdStart = (size / 3) - 1;
int weirdEnd = (end - weirdStart) - 1;
int weirdSize = (weirdEnd - start + 1);
weirdSort(arr, start, weirdEnd, weirdSize);
weirdSort(arr, weirdStart, end, weirdSize);
weirdSort(arr, start, weirdEnd, weirdSize);
}
else
bubbleSort(arr, start, end);
} // end of method
private static void bubbleSort(double arr[], int start, int end) {
int size = end - start + 1;
boolean noSwaps;
for (int i = start; i < size; i++) {
noSwaps = true;
for (int j = start + 1; j < size - i; j++) {
if (arr[j - 1] > arr[j]) {
swap(arr, j, j - 1);
noSwaps = false;
} // end of condition
} // end of (j) for loop
if (noSwaps) // If no two elements were swapped by inner loop, array is sorted
break;
} // end of (i) for loop
} // end of method
The problem is that it only sorts the array up to 2/3 of the first elements, the last 1/3 are unsorted (bubbleSort by itself works fine). I would really like to solve this on my own but I'm stuck, so I would apreciate any thoughts or suggestions on the matter but not a full solution.
After calling weirdSort for all the 3 parts, those parts will be sorted but it has to be arranged so that the whole array is sorted, just like in a mergesort. So after calling the weirdSort, you have to run a loop and convert those 3 independent sorted arrays into a single sorted array.
Your interpolation is wrong. Take an example,
weirdSort([...], 0, 11, 12):
weirdStart = 12 / 3 - 1 = 3
weirdEnd = 11 - 3 - 1 = 8
weirdSize = 8 - 0 + 1 = 9
// so far so good, but look at the second recursive call
weirdSort([...], 3, 11, 9):
weirdStart = 9 / 3 - 1 = 2 // Wrong!
// Other vars are now also wrong
You need to account for start when determining weirdStart and weirdEnd.
To get you started, you want something like,
third = (end - start + 1) / 3;
weirdStart = start + third;
weirdEnd = end - third;
In fact, don't pass size around at all, just compute it as end - start + 1.
You might want to adjust weirdStart/End by +/-1 depending on your specific needs.
Given is a sorted list (a[0],...,a[n-1]) of n integers. I need to find three different indices p, q, r such that the triplet (a[p],a[q],a[r]) satisfies the equation a[p]+a[q]+a[r]=0. Also, the sorted list can contain the same number more than once. The algorithm that is required needs to be quadratic.
I have found a solution (I'm definitely not saying that it is the most efficient one), but I'm quite sure that it's not quadratic (2 for-loops and a while-loop). Here is my code:
public ThreeSumIndices searchTriplet(List<Integer> list) {
for(int i=0; i<list.size()-1; i++){
int w = -list.get(i);
for(int j=i+1; j<list.size(); j++){
int k = 1;
while(j+k<list.size() && list.get(j)+list.get(j+k)!=w){
k++;
}
if(j+k==list.size()){
k = 1;
} else if(list.get(j)+list.get(j+k)==w){
return new ThreeSumIndices(i,j,j+k);
}
}
}
return null; //no indices found.
}
ThreeSumIndices is a seperate class. It returns the indices we're looking for in the form (p,q,r). Constructor parameters are three integer (= three indices).
Example: (-5, 1, 2, 3, 7) --> (0,2,3).
I'm fairly new to complexity analysis, so I was wondering whether my guess of this algorithm not being quadratic was correct or not.
If so, is there a way to get rid of a loop? Or maybe there's an alternative, but more efficient algorithm?
Thanks.
If the array is sorted then all you need to do is the following:
Run loop from i=0 to n-2.
Initialize two index variables l=i+1 and r=n-1
while:l<r, if ((sum = arr[i]+arr[l]+arr[r]) == 0):You got your answer
If sum is less than zero, increment l (l++), otherwise decrement r (r--)
scan all the elements.
for (int i=0; i < n-1; i++) {
int l = i + 1;
int r = n - 1;
int x = arr[i];
while (l < r){
if (x + arr[l] + arr[r] == 0) print()
else if(x + arr[l] + arr[r] < 0) l++;
else r--;
}
}
The time complexity of this code will be O(n^2) with space complexity of O(1)
I had to solve this for a coding interview, here's my python solution which has quadratic time complexity.
from collections import Counter
class Solution(object):
def threeSum(self, nums):
res = []
counts = Counter(nums)
num_counts = sorted(counts.items())
# If we pick 3 of the same nums
if counts[0] >= 3:
res.append([0] * 3)
for i, (first, first_count) in enumerate(num_counts):
# Pick two of these and one greater
if first_count >= 2 and first < 0 and -(first * 2) in counts:
res.append([first, first, -(first * 2)])
# Pick one and two greater
for j in range(i + 1, len(num_counts)):
second, second_count = num_counts[j]
# Pick two of these as second and third num
if second_count >= 2 and -first == 2 * second:
res.append([first, second, second])
# Pick this as second num and third which is greater
third = -(first + second)
if third > second and third in counts:
res.append([first, second, third])
return res
Basically, it counts the occurrences then sorts (number, count) tuples so that
[-1, 0, 1, 2, -1, -4]
becomes
[(-4, 1), (-1, 2), (0, 1), (1, 1), (2, 1)]
We then iterate trying to pick each number twice and third greater if possible and add that to the result. Then, we pick a number once and try to find two greater numbers which sum to zero.
I'm required to implement a programm that sorts numbers ranging from 0 to 99999 recursively (this is basically Radix sort). The process itself is kinda simpel: The user types in an array that contains those numbers in the main method. Then, the main method calls for the sort-method where I create a two-dimensional array named 'space' with 10 rows and 1 column. Then, I divide every number in the array by the digit, which would be 10.000 in the first run. So, for example, 23456 / 10000 = 2,3456 = 2 (in java), hence, the programm puts this number in space[2][0], so in the second row. Then, we take this entire row and extend it, which is done in the putInBucket-method. We do this in order to make sure that we can put another number into the same row.
We do this for every number that is inside the 'numbers'-array. Then, we want to work with these rows and sort them again by the same principle, but now we take a look at the second digit. We want to do this from left to right, not from right to left. So, if our second row would look like this
[23456, 24567],
we'd want to compare the 3 and the 4, which leads to 23456 < 24567.
We do this with the help of the recursive call at the end of the sort method. Now, this is where I am lost. I simply don't know how to manipulate the digit-variable in order to be able to work with the second, third, ... digit of each number. In the first run, as you see, this can be simply done by dividing through 10.000, but I didn't find a way to go further from here.
Please note: Yes, this is a homework question, hence, I'm only allowed to use primitives here. We didn't go through stuff like math.pow(...) yet. Thanks in advance!
public static int[] sort(int[] numbers, int digit) {
if (numbers.length == 0)
return numbers;
int[][]space = new int[10][1];
int i, j = 0;
for (j = 0; j < numbers.length; j++) {
i = numbers[j] / digit;
space[i][0] = numbers[j];
space[i] = putInBucket(space[i], numbers[j]);
}
for (i = 0; i < space[i].length; i++) {
sort(space[i], digit); //not sure how to work with digit here
}
return ... //not sure what to return here
}
private static int[] putInBucket(int[] bucket, int number) {
int[] bucket_new = new int[bucket.length+1];
for (int i = 1; i < bucket_new.length; i++) {
bucket_new[i] = bucket[i-1];
}
return bucket_new;
}
public static void main (String [] argv) {
int[] numbers = IO.readInts("Numbers: ");
int digit = 10000;
int[] bucket = sort(numbers, digit);
}
To extract the last digit, the remainder operator % is your friend:
123 % 10 == 3
if you haven't covered the % operator yet, you can use
123 % 10 == 123 - (123 / 10 * 10) == 3
To extract another digit, you can first move it to the end with /:
123 / 10 == 12
12 % 10 == 2
You can therefore extract an arbitrary digit using
(number / mask) % 10
where mask ∈ {..., 10000, 1000, 100, 10, 1}.
Extra credit
Radix sort is usually implemented in the binary number system instead because a binary digit (or a sequence thereof) can be extracted without performing a division, which is more efficient:
x % 16 == x & 15;
x \ 16 == x >> 4;
Also, if you are implementing this for real, you'd need a more efficient way to grow buckets (your implementation takes O(n) to add a single element to the bucket, adding n elements to the bucket therefore takes O(n^2), which makes your radix sort slower than insertion sort). Dynamic arrays are usually implemented with a more efficient geometric expansion.
This should work:
public static int[] sort(int[] numbers, int digit) {
if (numbers.length == 0 || digit <= 0)
return numbers;
int[][]space = new int[10][10];
int[] len = new int[10];
int i, j = 0;
for (j = 0; j < numbers.length; j++) {
i = (numbers[j] / digit) % 10;
len[i]++;
for (int k = len[i] - 1; k > 0; k--) {
space[i][k] = space[i][k - 1];
}
space[i][0] = numbers[j];
}
for (i = 0; i < 10; i++) {
int[] bucket = new int[len[i]];
for (int k = 0; k < len[i]; k++)
bucket[k] = space[i][k];
space[i] = sort(bucket, digit / 10);
}
int k = 0;
for (i = 0; i < 10; i++) {
for (j = 0; j < len[i]; j++) {
numbers[k] = space[i][j];
k++;
}
}
return numbers;
}
a) Firstly, space is allocated as having only one column. So, space[i] = bucket will not work.
Instead, you could declare it as int[10][10]. (Note: it will only support max of 10 values in one bucket). Or you may allocate new arrays programmatically. Or of course, a List might be better suited.
b) i = (numbers[j] / digit) % 10;
To get the required digit only. For eg: if the number is 12130, and digit = 1000, we want to set i to 2, not 12.
c) putInBucket replaced with an in-place loop.
d) For each bucket of space, we sort it by one digit lower by calling sort recursively.
e) Finally, the result to be returned (numbers), can be created by looping through space from digit 0 to 9.
Note:
This solution could probably be made better.
For example, if you were given {1,2} as the small array and {1,2,3,4,1,2,1,3} as the big one, then it would return 2.
This is probably horribly incorrect:
public static int timesOccur(int[] small, int big[]) {
int sum= 0;
for (int i=0; i<small.length; i++){
int currentSum = 0;
for (int j=0; j<big.length; j++){
if (small[i] == big[j]){
currentSum ++;
}
sum= currentSum ;
}
}
return sum;
}
As #AndyTurner mentioned, your task can be reduced to the set of well-known string matching algorithms.
As I can understand you want solution faster than O(n * m).
There are two main approaches. First involves preprocessing text (long array), second involves preprocessing search pattern (small array).
Preprocessing text. By this I mean creating suffix array or LCP from your longer array. Having this data structure constructed you can perform a binary search to find your your substring. The most efficient time you can achieve is O(n) to build LCP and O(m + log n) to perform the search. So overall time is O(n + m).
Preprocessing pattern. This means construction DFA from the pattern. Having DFA constructed it takes one traversal of the string (long array) to find all occurrences of substring (linear time). The hardest part here is to construct the DFA. Knuth-Morris-Pratt does this in O(m) time, so overall algorithm running time will be O(m + n). Actually KMP algorithm is most probably the best available solution for this task in terms of efficiency and implementation complexity. Check #JuanLopes's answer for concrete implementation.
Also you can consider optimized bruteforce, for example Boyer-Moore, it is good for practical cases, but it has O(n * m) running time in worst case.
UPD:
In case you don't need fast approaches, I corrected your code from description:
public static int timesOccur(int[] small, int big[]) {
int sum = 0;
for (int i = 0; i < big.length - small.length + 1; i++) {
int j = 0;
while (j < small.length && small[j] == big[i + j]) {
j++;
}
if (j == small.length) {
sum++;
}
}
return sum;
}
Pay attention on the inner while loop. It stops as soon as elements don't match. It's important optimization, as it makes running time almost linear for best cases.
upd2: inner loop explanation.
The purpose of inner loop is to find out if smaller array matches bigger array starting from position i. To perform that check index j is iterated from 0 to length of smaller array, comparing the element j of the smaller array with the corresponding element i + j of the bigger array. Loop proceeds when both conditions are true at the same time: j < small.length and corresponding elements of two arrays match.
So loop stops in two situations:
j < small.length is false. This means that j==small.length. Also it means that for all j=0..small.length-1 elements of the two arrays matched (otherwise loop would break earlier, see (2) below).
small[j] == big[i + j] is false. This means that match was not found. In this case loop will break before j reaches small.length
After the loop it's sufficient to check whether j==small.length to know which condition made loop to stop and hence know whether match was found or not for current position i.
This is a simple subarray matching problem. In Java you can use Collections.indexOfSublist, but you would have to box all the integers in your array. An option is to implement your own array matching algorithm. There are several options, most string searching algorithms can be adapted to this task.
Here is an optimized version based on the KMP algorithm. In the worst case it will be O(n + m), which is better than the trivial algorithm. But it has the downside of requiring extra space to compute the failure function (F).
public class Main {
public static class KMP {
private final int F[];
private final int[] needle;
public KMP(int[] needle) {
this.needle = needle;
this.F = new int[needle.length + 1];
F[0] = 0;
F[1] = 0;
int i = 1, j = 0;
while (i < needle.length) {
if (needle[i] == needle[j])
F[++i] = ++j;
else if (j == 0)
F[++i] = 0;
else
j = F[j];
}
}
public int countAt(int[] haystack) {
int count = 0;
int i = 0, j = 0;
int n = haystack.length, m = needle.length;
while (i - j <= n - m) {
while (j < m) {
if (needle[j] == haystack[i]) {
i++;
j++;
} else break;
}
if (j == m) count++;
else if (j == 0) i++;
j = F[j];
}
return count;
}
}
public static void main(String[] args) {
System.out.println(new KMP(new int[]{1, 2}).countAt(new int[]{1, 2, 3, 4, 1, 2, 1, 3}));
System.out.println(new KMP(new int[]{1, 1}).countAt(new int[]{1, 1, 1}));
}
}
Rather than posting a solution I'll provide some hints to get your moving.
It's worth breaking the problem down into smaller pieces, in general your algorithm should look like:
for each position in the big array
check if the small array matches that position
if it does, increment your counter
The smaller piece is then checking if the small array matches a given position
first check if there's enough room to fit the smaller array
if not then the arrays don't match
otherwise for each position in the smaller array
check if the values in the arrays match
if not then the arrays don't match
if you get to the end of the smaller array and they have all matched
then the arrays match
Though not thoroughly tested I believe this is a solution to your problem. I would highly recommend using Sprinters pseudocode to try and figure this out yourself before using this.
public static void main(String[] args)
{
int[] smallArray = {1,1};
int[] bigArray = {1,1,1};
int sum = 0;
for(int i = 0; i < bigArray.length; i++)
{
boolean flag = true;
if(bigArray[i] == smallArray[0])
{
for(int x = 0; x < smallArray.length; x++)
{
if(i + x >= bigArray.length)
flag = false;
else if(bigArray[i + x] != smallArray[x])
flag = false;
}
if(flag)
sum += 1;
}
}
System.out.println(sum);
}
}
I'm reading Cormen's "Introduction to Algorithms".
For the linear algorithm for Max Sum Subarray problem I came up with my own solution. Didn't check existing one (Kadena's) before implementing.
Now I'm testing it with different test scenarios and always have better results than Kadena's. I don't believe in such a luck, but can't find what have I missed. Could you take a look whether it is a working solution?
public void findMaxSubarray(Number[] numbers) {
int maxSum = Integer.MIN_VALUE;
int left = 0;
int right = numbers.length - 1;
int i = 0;
int j = i + 1;
int sum = numbers[i].intValue();
while (i < numbers.length) {
if (maxSum < sum) {
maxSum = sum;
left = i;
right = j - 1;
}
if (j >= numbers.length)
return;
sum = sum + numbers[j].intValue();
if (sum <= 0) {
// ignoring "first" negative numbers. shift i to first non-negative
while (numbers[j].intValue() <= 0) {
if (maxSum < numbers[j].intValue()) {
maxSum = numbers[j].intValue();
left = j;
right = j;
}
if (++j >= numbers.length)
return;
}
i = ++j;
sum = 0;
}
j++;
}
System.out.println(String.format("Max subarray is %d, [%d; %d]", maxSum, left, right));
}
Update
The idea of code is to keep in track only one subarray, and adding to its' tail numbers, when numbers are that low that sum becomes negative - set beginning of array after the tail.
Additionally negative items in the beginning are being ignored. head of subarray is just shifted forward.
Everytime sum appears to be maximum - maxSum and limits are updated.
shift i() --to first non negative number
from j = i+1 up to N.length
sum + N[j]
if sum <= 0
i = j+1
if N[i] < 0
shift i()
sum = 0
I think your algorithm is basically sound, but it has two bugs that I can see:
On the input 1 -2 10 3, it will skip over the 10 and output 3. I think you can fix this by changing i = ++j; to i = j;.
In 2 different places you return if j goes past the end, which will cause no output to be produced at all! (This will happen if, e.g., a long list of negative numbers appears at the end of the list.)
Also I don't expect it to be faster (or slower, for that matter) than Kadane's. Summing two numbers is a fast operation, as fast as copying one variable to another, which is what you are doing when you shift the start of the subarray.