how to find near value? - c

Iam trying to see if there is a shorter method in being able to find the nearest value in a linear search algorithm if the value you are searching for doesnt exist,without using any searching / sorting built in methods. Thank you.
Here is my current method below,although my attempt seems inefficent.
(iam assuming the array is already sorted)
public void LinearSearchNearest(int[] data, int target, string dataname)
{
Console.WriteLine(dataname + ": ");
int StepsNearest = 0;
int n = data.Length;
StepsNearest++;
// Check for corner cases (check the value is actually within range of the array)
if (target < data[0])
{
Console.WriteLine($"Closest value : {data[0]}, Position : {1} (value outside of array bounds) ");
Console.WriteLine($"Num of Steps is : {StepsNearest}");
return;
}
if (target > data[n - 1])
{
Console.WriteLine($"Closest value : {data[n - 1]}, Position : {n} (value outside of array bounds) ");
Console.WriteLine($"Num of Steps is : {StepsNearest}");
return;
}
int closestVal = 0;
int position = 0;
int found = 0;
int targetCount = 0;
Console.Write("Value is at positions : ");
for (int i = 0; i < data.Length; i++)
{
StepsNearest++;
if (data[i] == target)
{
targetCount++;
found++;
Console.Write($"{i + 1}, ");
}
else
{
StepsNearest++;
// Compare closest value currently to new value to see which one is closer to target
long along = data[i];
long blong = closestVal;
long clong = target;
var distanceA = Math.Abs(clong - along);
var distanceB = Math.Abs(clong - blong);
if (distanceA < distanceB)
{
closestVal = data[i];
position = i + 1;
}
}
}
// Check if target value was found or not in the array given
string result = (found == 0) ? $"Closest value : {closestVal}, Position : {position} " +
$"\nNum of Steps is : {StepsNearest}" : $"\nNum of Steps is : {StepsNearest}";
Console.WriteLine(result);
}
UPDATE CODE
public void LinearSearchNearest(int[] data, int target, string dataname)
{
Console.WriteLine(dataname + ": ");
StepsNearest = 0;
int closestVal = 0;
int position = 0;
int found = 0;
int minDistance = int.MaxValue;
Console.Write("Value is at positions : ");
for (int i = 0; i < data.Length; i++)
{
StepsNearest++;
if (data[i] == target)
{
found = 1;
Console.Write($"{i + 1}, ");
}
else
{
StepsNearest++;
// Compare closest value currently to new value to see which one is closer to target
int distance = System.Math.Abs(data[i] - target);
if (distance < minDistance)
{
minDistance = distance;
closestVal = data[i];
position = i + 1;
}
}
}
// Check if target value was found or not in the array given
string result = (found == 0) ? $"Closest value : {closestVal}, Position : {position} " +
$"\nNum of Steps is : {StepsNearest}" : $"\nNum of Steps is : {StepsNearest}";
Console.WriteLine(result);
}

If the array is assumed to be sorted as you said in the comments, then you could just walk through the array until you find a value that's equal to or larger than the target. If the value is equal, then of course we'd return that index.
If the value is larger, then we compare the difference of this value and the target with the difference of the previous value and the target, and return the index of the value with the smallest difference.
If we never find an equal or larger value, then we return the last index:
public int GetIndexOfNearest(int[] data, int target)
{
if (data == null) throw new ArgumentNullException(nameof(data));
if (target <= data[0]) return 0;
if (target >= data[data.Length - 1]) return data.Length - 1;
for (int i = 0; i < data.Length; i++)
{
// If we find a match, return that index
if (data[i] == target) return i;
// If this value is greater than the target then we either
// return this index or the previous index, depending
// on which one has the smallest diff with the target
if (data[i] > target)
{
var thisDiff = Math.Abs(data[i] - target);
var prevDiff = Math.Abs(data[i - 1] - target);
if (thisDiff < prevDiff) return i;
else return i - 1;
}
}
// We should never get here, since this is the case where all the items are smaller
// than the target, which we checked in the third line, but the compiler requires it
return data.Length - 1;
}

You can do all in one iteration. This will either find the first exact match or the nearest element to the search value in an UNORDERED array. If there are multiple elements with the same distance to the search value, it will find the first one.
let values = [...]; //your value list
let search = ...; //your value to search
let index = 0; //index where element is found
for (let i = 0; i < values.length; i++) {
// if the current element is an exact match, set the index to i
// and break the loop
if (values[i] == search) {
index = i;
break;
}
// else if current element is "nearer" to the searchvalue than
// the previously remembered, remember the current index
else if (abs(values[i] - search) < abs(values[index] - search)) {
index = i;
}
}
If you assume, that your array is already sorted you could do it as follows
let values = [...]; //your value list
let search = ...; //your value to search
let index = 0; //index where element is found
for (let i = 0; i < values.length; i++) {
// if the current element is an exact match, set the index to i
// and break the loop
if (values[i] == search) {
index = i;
break;
}
// while the current value is less then the search value,
// just remember the index
else if (values[i] < search) {
index = i;
}
// if the current value is greater then the search value
// check whether the previous or the current element is nearer to the search value
else if (values[i] > search) {
index = abs(search - values[i]) < abs(search - values[index])
? i
: index;
break;
}
}

Shorter? Maybe. What I have to offer is (hopefully) faster.
Let's summarize what you are looking for:
IN: Array of int, sorted (ascending order)
IN: target int value.
OUT: Array of all indices with values with minimal distance to target.
Given, that the data contains sorted data allows us to pick an algorithm, which performs more quickly than linear search. Linear search (O(N)) would be our only choice were the data in the array not sorted.
But as data is sorted, we can do binary search, which has O(log n) runtime.
With the help of binary search, we can find 1 or 2 candidates, which have the minimal distance to target.
Then, it is just a matter of looping towards the left and towards the right as long as there are values with that same minimal distance as our minimal candidate had.
A wall of code says more than 1000 words, right? Here we go:
using System;
using System.Linq;
using System.Collections.Generic;
namespace nearest
{
class Program
{
static int BinarySearchClosest( int[] data, int target, int left, int right)
{
if (right < left)
throw new ArgumentException(nameof(right));
if ((right - left) < 2)
return left;
var mid = left + (right - left) / 2;
if ( target > data[mid])
return BinarySearchClosest(data,target, mid, right);
else
return BinarySearchClosest(data,target, left, mid);
}
static int IndexOfClosestExistingValue( int[] data, int target) {
if (null == data) throw new ArgumentNullException(nameof(data));
if (0 == data.Length)
return -1;
// 1.Do a binary search to get within the same zip code of what
// we are looking for.
var ballpark = BinarySearchClosest(data, target, 0, data.Length);
// 2. we are close. The real minimum distance is either
// Math.Abs(data[ballpark]-target) or
// (Math.Abs(data[ballpark+1]-target) IFF (ballpark+1) < data.Length).
var minDist = Math.Abs(data[ballpark]-target);
var imin = ballpark;
if (((imin+1) < data.Length) && (Math.Abs(data[imin+1]-target) < minDist)) {
minDist = Math.Abs(data[imin+1]-target);
imin = imin + 1;
}
return imin;
}
static int[] IndicesOfClosestExistingValues( int[] data, int target)
{
List<int> result = new List<int>();
var imin = IndexOfClosestExistingValue(data, target);
if (imin >= 0) {
var minDist = Math.Abs(data[imin]-target);
result.Add(imin);
// Add equally good matches to the left of imin to the result.
for (var i = imin - 1;
i >= 0 && Math.Abs(data[i]-target) == minDist; i--) {
result.Add(i);
}
// Add equally good matches to the right of imin to the result.
for (var i = imin +1;
i < data.Length && Math.Abs(data[i]-target) == minDist; i++) {
result.Add(i);
}
}
return result.ToArray();
}
internal struct TestCase {
internal int[] data;
internal int target;
internal int[] expected;
}
static string TestCaseToString( TestCase tc) {
var sb = new System.Text.StringBuilder();
sb.AppendFormat(
"TestCase{{ data = {{{0}}}, target = {1}, expected = {{{2}}}}}",
string.Join(", ", tc.data),
tc.target,
string.Join(", ", tc.expected));
return sb.ToString();
}
static void Main(string[] args)
{
TestCase[] testCases =
{ new TestCase{
data = new int[]{},
target = 42,
expected = new int[]{} }, // data.Length == 0
new TestCase{
data = new int[]{1},
target = 42,
expected = new int[]{0} }, // data.Length == 1
new TestCase{
data = new int[]{1, 41, 45, 99},
target = 42,
expected = new int[]{1} }, // somewhere in the middle
new TestCase{
data = new int[]{100,101,102},
target = 42,
expected = new int[]{0} }, // far left
new TestCase{
data = new int[]{1,2,3},
target = 42,
expected = new int[]{2} }, // far right
new TestCase{
data = new int[]{1,1,1,1},
target = 42,
expected = new int[]{3,2,1,0} }, // multiple matches left
new TestCase{
data = new int[]{100,100,100,100},
target = 42,
expected = new int[]{0,1,2,3} }, // multiple matches right
new TestCase{
data = new int[]{41,41,41,41,43,43,43,43},
target = 42,
expected = new int[]{3,2,1,0,4,5,6,7} }, // multiple matches both sides
new TestCase{
data = new int[]{4,6},
target = 5,
expected = new int[]{0,1} } // multiple disjoint matches
};
int failCounter = 0;
int testCaseIndex = 0;
foreach ( var tc in testCases ) {
try {
int[] actual =
IndicesOfClosestExistingValues(tc.data, tc.target);
bool verdict = Enumerable.SequenceEqual(actual, tc.expected);
if (false == verdict)
failCounter++;
Console.WriteLine(
"{1}: {0}, actual = {{{2}}}",
TestCaseToString(tc),
verdict == true ? "OK" : "FAILED",
string.Join(", ", actual));
}
catch (FormatException) {
Console.WriteLine("{0}: FAULTED", testCaseIndex);
}
catch (ArgumentNullException) {
Console.WriteLine("{0}: FAULTED (argument null)", testCaseIndex);
}
finally {
testCaseIndex++;
}
}
Console.WriteLine("Done. ({0} tests failed.)", failCounter);
}
}
}
I did not use C# in many years and if you want to explore algorithms without a lot of lines of code and typing, I strongly recommend to use a more terse language (unless you really want to learn C#). F# is an attractive alternative as it uses the same run time, has the same default libraries and is much more easy on your fingers.

Related

How do I find the largest x,y and smallest x,y in a 2 dimensional array?

List<List<double>> intArr = [[448.0, 392.5], [465.5, 392.5], [493.5, 388.0], [536.0, 383.0], [609.5, 374.0], [667.5, 371.5], [714.5, 370.0], [771.0, 375.0], [804.0, 387.5], [821.0, 409.0], [828.0, 434.5], [833.0, 471.5], [834.0, 511.0], [833.0, 546.5], [829.5, 607.5], [819.5, 650.0], [804.5, 697.0], [799.5, 721.0], [796.5, 737.0], [795.0, 746.0], [792.5, 757.5], [791.0, 765.0]]
The above is my 2D ours. I want to find the smallest x and smallest y in this array and keep it as 2 in a new array. How can I do it. I am sharing a piece as an example below.
List<List> newList [[834,757.5],[448,370]]
List biggestPair = intArr[0];
List smallestPair = intArr[0];
for (int i = 0; i < intArr.length; i++) {
List pair = intArr[i];
if (pair[0] >= biggestPair[0]) {
if (pair[1] < biggestPair[1]) {
continue;
}
biggestPair = pair;
} else if (pair[0] < smallestPair[0]) {
if (pair[1] > smallestPair[1]) {
continue;
}
smallestPair = pair;
}
}
newArr = [biggestPair, smallestPair];
print(newArr);
The above code does not give the exact result I want. The above code gives the following result, but this result is wrong.
[[834.0, 511.0], [448.0, 392.5]]
The reason for your code is not working as intended is because what you want is not part of your existing set of points since your result is actually a new generated point where you combine data from other points.
But in your code you are doing biggestPair = pair; and smallestPair = pair; where you save points form your list of points and uses that as result.
I would rewrite the code into something like this making use of dart:math:
void main() {
var maxX = intArr[0][0];
var maxY = intArr[0][0];
var minX = intArr[0][1];
var minY = intArr[0][1];
for (final pair in intArr) {
final x = pair[0];
final y = pair[1];
maxX = max(maxX, x);
maxY = max(maxY, y);
minX = min(minX, x);
minY = min(minY, y);
}
final result = [[maxX, maxY], [minX, minY]];
print(result); // [[834.0, 765.0], [392.5, 370.0]]
}

The longest sub-array with switching elements

An array is called "switching" if the odd and even elements are equal.
Example:
[2,4,2,4] is a switching array because the members in even positions (indexes 0 and 2) and odd positions (indexes 1 and 3) are equal.
If A = [3,7,3,7, 2, 1, 2], the switching sub-arrays are:
== > [3,7,3,7] and [2,1,2]
Therefore, the longest switching sub-array is [3,7,3,7] with length = 4.
As another example if A = [1,5,6,0,1,0], the the only switching sub-array is [0,1,0].
Another example: A= [7,-5,-5,-5,7,-1,7], the switching sub-arrays are [7,-1,7] and [-5,-5,-5].
Question:
Write a function that receives an array and find its longest switching sub-array.
I would like to know how you solve this problem and which strategies you use to solve this with a good time complexity?
I am assuming that the array is zero indexed .
if arr.size <= 2
return arr.size
else
ans = 2
temp_ans = 2 // We will update ans when temp_ans > ans;
for i = 2; i < arr.size ; ++i
if arr[i] = arr[i-2]
temp_ans = temp_ans + 1;
else
temp_ans = 2;
ans = max(temp_ans , ans);
return ans;
I think this should work and I don't think it needs any kind of explanation .
Example Code
private static int solve(int[] arr){
if(arr.length == 1) return 1;
int even = arr[0],odd = arr[1];
int start = 0,max_len = 0;
for(int i=2;i<arr.length;++i){
if(i%2 == 0 && arr[i] != even || i%2 == 1 && arr[i] != odd){
max_len = Math.max(max_len,i - start);
start = i-1;
if(i%2 == 0){
even = arr[i];
odd = arr[i-1];
}else{
even = arr[i-1];
odd = arr[i];
}
}
}
return Math.max(max_len,arr.length - start);
}
It's like a sliding window problem.
We keep track of even and odd equality with 2 variables, even and odd.
Whenever we come across a unmet condition, like index even but not equal with even variable and same goes for odd, we first
Record the length till now in max_len.
Reset start to i-1 as this is need incase of all elements equal.
Reset even and odd according to current index i to arr[i] and arr[i-1] respectively.
Demo: https://ideone.com/iUQti7
I didn't analyse the time complexity, just wrote a solution that uses recursion and it works (I think):
public class Main
{
public static int switching(int[] arr, int index, int end)
{
try
{
if (arr[index] == arr[index+2])
{
end = index+2;
return switching(arr, index+1, end);
}
} catch (Exception e) {}
return end;
}
public static void main(String[] args)
{
//int[] arr = {3,2,3,2,3};
//int[] arr = {3,2,3};
//int[] arr = {4,4,4};
int[] arr = {1,2,3,4,5,4,4,7,9,8,10};
int best = -1;
for (int i = 0; i < arr.length; i++)
best = Math.max(best, (switching(arr, i, 0) - i));
System.out.println(best+1); // It returns, in this example, 3
}
}
int switchingSubarray(vector<int> &arr, int n) {
if(n==1||n==2) return n;
int i=0;
int ans=2;
int j=2;
while(j<n)
{
if(arr[j]==arr[j-2]) j++;
else
{
ans=max(ans,j-i);
i=j-1;
j++;
}
}
ans=max(ans,j-i);
return ans;
}
Just using sliding window technique to solve this problems as element at j and j-2 need to be same.
Try to dry run on paper u will surely get it .
# Switching if numbers in even positions equal to odd positions find length of longest switch in continuos sub array
def check(t):
even = []
odd = []
i = 0
while i < len(t):
if i % 2 == 0:
even.append(t[i])
else:
odd.append(t[i])
i += 1
if len(set(even)) == 1 and len(set(odd)) == 1:
return True
else:
return False
def solution(A):
maxval = 0
if len(A) == 1:
return 1
for i in range(0, len(A)):
for j in range(0, len(A)):
if check(A[i:j+1]) == True:
val = len(A[i:j+1])
print(A[i:j+1])
if val > maxval:
maxval = val
return maxval
A = [3,2,3,2,3]
A = [7,4,-2,4,-2,-9]
A=[4]
A = [7,-5,-5,-5,7,-1,7]
print(solution(A))

Transform an array to another array by shifting value to adjacent element

I am given 2 arrays, Input and Output Array. The goal is to transform the input array to output array by performing shifting of 1 value in a given step to its adjacent element. Eg: Input array is [0,0,8,0,0] and Output array is [2,0,4,0,2]. Here 1st step would be [0,1,7,0,0] and 2nd step would be [0,1,6,1,0] and so on.
What can be the algorithm to do this efficiently? I was thinking of performing BFS but then we have to do BFS from each element and this can be exponential. Can anyone suggest solution for this problem?
I think you can do this simply by scanning in each direction tracking the cumulative value (in that direction) in the current array and the desired output array and pushing values along ahead of you as necessary:
scan from the left looking for first cell where
cumulative value > cumulative value in desired output
while that holds move 1 from that cell to the next cell to the right
scan from the right looking for first cell where
cumulative value > cumulative value in desired output
while that holds move 1 from that cell to the next cell to the left
For your example the steps would be:
FWD:
[0,0,8,0,0]
[0,0,7,1,0]
[0,0,6,2,0]
[0,0,6,1,1]
[0,0,6,0,2]
REV:
[0,1,5,0,2]
[0,2,4,0,2]
[1,1,4,0,2]
[2,0,4,0,2]
i think BFS could actually work.
notice that n*O(n+m) = O(n^2+nm) and therefore not exponential.
also you could use: Floyd-Warshall algorithm and Johnson’s algorithm, with a weight of 1 for a "flat" graph, or even connect the vertices in a new way by their actual distance and potentially save some iterations.
hope it helped :)
void transform(int[] in, int[] out, int size)
{
int[] state = in.clone();
report(state);
while (true)
{
int minPressure = 0;
int indexOfMinPressure = 0;
int maxPressure = 0;
int indexOfMaxPressure = 0;
int pressureSum = 0;
for (int index = 0; index < size - 1; ++index)
{
int lhsDiff = state[index] - out[index];
int rhsDiff = state[index + 1] - out[index + 1];
int pressure = lhsDiff - rhsDiff;
if (pressure < minPressure)
{
minPressure = pressure;
indexOfMinPressure = index;
}
if (pressure > maxPressure)
{
maxPressure = pressure;
indexOfMaxPressure = index;
}
pressureSum += pressure;
}
if (minPressure == 0 && maxPressure == 0)
{
break;
}
boolean shiftLeft;
if (Math.abs(minPressure) > Math.abs(maxPressure))
{
shiftLeft = true;
}
else if (Math.abs(minPressure) < Math.abs(maxPressure))
{
shiftLeft = false;
}
else
{
shiftLeft = (pressureSum < 0);
}
if (shiftLeft)
{
++state[indexOfMinPressure];
--state[indexOfMinPressure + 1];
}
else
{
--state[indexOfMaxPressure];
++state[indexOfMaxPressure + 1];
}
report(state);
}
}
A simple greedy algorithm will work and do the job in minimum number of steps. The function returns the total numbers of steps required for the task.
int shift(std::vector<int>& a,std::vector<int>& b){
int n = a.size();
int sum1=0,sum2=0;
for (int i = 0; i < n; ++i){
sum1+=a[i];
sum2+=b[i];
}
if (sum1!=sum2)
{
return -1;
}
int operations=0;
int j=0;
for (int i = 0; i < n;)
{
if (a[i]<b[i])
{
while(j<n and a[j]==0){
j++;
}
if(a[j]<b[i]-a[i]){
operations+=(j-i)*a[j];
a[i]+=a[j];
a[j]=0;
}else{
operations+=(j-i)*(b[i]-a[i]);
a[j]-=(b[i]-a[i]);
a[i]=b[i];
}
}else if (a[i]>b[i])
{
a[i+1]+=(a[i]-b[i]);
operations+=(a[i]-b[i]);
a[i]=b[i];
}else{
i++;
}
}
return operations;
}
Here -1 is a special value meaning that given array cannot be converted to desired one.
Time Complexity: O(n).

Minimum number of swaps needed to sort the array

I have an array of size n, which contain elements from 1 to n, in random order. So, we'd have as input an unordered array of integers.
Considering I can swap any two elements any number of times, how can I find minimum numbers of such swap to make array sorted?
This can be done in O(n). Assuming elements are in range 1 to n and there're no duplicates.
noofswaps = 0
for i in range(len(A)):
while A[i] != i + 1:
temp = A[i]
A[i] = A[A[i] - 1]
A[temp - 1] = temp
noofswaps += 1
print noofswaps
static int minimumSwaps(int[] arr) {
int swap=0;
boolean newarr[]=new boolean[arr.length];
for(int i=0;i<arr.length;i++){
int j=i,count=0;
while(!newarr[j]){
newarr[j]=true;
j=arr[j]-1;
count++;
}
if(count!=0)
swap+=count-1;
}
return swap;
}
I'll try to answer this question using javascript.
This is most optimal code I have tried so far :
function minimumSwaps(arr) {
var arrLength = arr.length;
// create two new Arrays
// one record value and key separately
// second to keep visited node count (default set false to all)
var newArr = [];
var newArrVisited = [];
for (let i = 0; i < arrLength; i++) {
newArr[i]= [];
newArr[i].value = arr[i];
newArr[i].key = i;
newArrVisited[i] = false;
}
// sort new array by value
newArr.sort(function (a, b) {
return a.value - b.value;
})
var swp = 0;
for (let i = 0; i < arrLength; i++) {
// check if already visited or swapped
if (newArr[i].key == i || newArrVisited[i]) {
continue;
}
var cycle = 0;
var j = i;
while (!newArrVisited[j]) {
// mark as visited
newArrVisited[j] = true;
j = newArr[j].key; //assign next key
cycle++;
}
if (cycle > 0) {
swp += (cycle > 1) ? cycle - 1 : cycle;
}
}
return swp;
}
reference -1
reference -2
Hackerrank Python code for minimum swaps 2 using hashmaps
length = int(input())
arr= list(map(int,input().split()))
hashmap = {}
for i in range(0,len(arr)):
hashmap[i+1] = [arr[i],False]
swap_count = 0
for e_pos, e_val in hashmap.items():
if e_val[1] == False:
e_val[1] = True
if e_pos == e_val[0]:
continue
else:
c = e_val[0]
while hashmap[c][1] == False:
hashmap[c][1] = True
b = hashmap[c][0]
c = b
swap_count+=1
print(swap_count)
There's an interesting take in GeeksForGeeks with
Time Complexity: O(N) where N is the size of the array.
Auxiliary Space: O(1)
The used approach was
For each index in arr[], check if the current element is in it’s right position or not. Since the array contains distinct elements from 1 to N, we can simply compare the element with it’s index in array to check if it is at its right position.
If current element is not at it’s right position then swap the element with the element which has occupied its place (using temp variable)
Else check for next index (i += 1)
This is the code
def minimumSwaps(arr):
min_num_swaps = 0;
i = 0;
while (i < len(arr)):
if (arr[i] != i + 1):
while (arr[i] != i + 1):
temp = 0;
temp = arr[arr[i] - 1];
arr[arr[i] - 1] = arr[i];
arr[i] = temp;
min_num_swaps += 1;
i += 1;
return min_num_swaps;
that could easily be updated to
Remove semicolons
Remove the need for temp
Substitute len(arr) with a given integer input n with the size of the array
def minimumSwaps(arr):
min_num_swaps = 0
i = 0
while (i < n-1):
if (arr[i] != i + 1):
while (arr[i] != i + 1):
arr[arr[i] - 1], arr[i] = arr[i], arr[arr[i] - 1]
min_num_swaps += 1
i += 1;
return min_num_swaps
They both are gonna pass all the current 15 Test cases in HackerRank
Here is my code for minimumsawap function using java 7
static int minimumSwaps(int[] arr) {
int c=0;
for(int i=0;i<arr.length;i++){
if(arr[i]!=(i+1)){
int t= arr[i];
arr[i]=arr[t-1];
arr[t-1]=t;
c++;
i=0;
}
}
return c;
}

Find length of smallest window that contains all the characters of a string in another string

Recently i have been interviewed. I didn't do well cause i got stuck at the following question
suppose a sequence is given : A D C B D A B C D A C D
and search sequence is like: A C D
task was to find the start and end index in given string that contains all the characters of search string preserving the order.
Output: assuming index start from 1:
start index 10
end index 12
explanation :
1.start/end index are not 1/3 respectively because though they contain the string but order was not maintained
2.start/end index are not 1/5 respectively because though they contain the string in the order but the length is not optimum
3.start/end index are not 6/9 respectively because though they contain the string in the order but the length is not optimum
Please go through How to find smallest substring which contains all characters from a given string?.
But the above question is different since the order is not maintained. I'm still struggling to maintain the indexes. Any help would be appreciated . thanks
I tried to write some simple c code to solve the problem:
Update:
I wrote a search function that looks for the required characters in correct order, returning the length of the window and storing the window start point to ìnt * startAt. The function processes a sub-sequence of given hay from specified startpoint int start to it's end
The rest of the algorithm is located in main where all possible subsequences are tested with a small optimisation: we start looking for the next window right after the startpoint of the previous one, so we skip some unnecessary turns. During the process we keep track f the 'till-now best solution
Complexity is O(n*n/2)
Update2:
unnecessary dependencies have been removed, unnecessary subsequent calls to strlen(...) have been replaced by size parameters passed to search(...)
#include <stdio.h>
// search for single occurrence
int search(const char hay[], int haySize, const char needle[], int needleSize, int start, int * startAt)
{
int i, charFound = 0;
// search from start to end
for (i = start; i < haySize; i++)
{
// found a character ?
if (hay[i] == needle[charFound])
{
// is it the first one?
if (charFound == 0)
*startAt = i; // store starting position
charFound++; // and go to next one
}
// are we done?
if (charFound == needleSize)
return i - *startAt + 1; // success
}
return -1; // failure
}
int main(int argc, char **argv)
{
char hay[] = "ADCBDABCDACD";
char needle[] = "ACD";
int resultStartAt, resultLength = -1, i, haySize = sizeof(hay) - 1, needleSize = sizeof(needle) - 1;
// search all possible occurrences
for (i = 0; i < haySize - needleSize; i++)
{
int startAt, length;
length = search(hay, haySize, needle, needleSize, i, &startAt);
// found something?
if (length != -1)
{
// check if it's the first result, or a one better than before
if ((resultLength == -1) || (resultLength > length))
{
resultLength = length;
resultStartAt = startAt;
}
// skip unnecessary steps in the next turn
i = startAt;
}
}
printf("start at: %d, length: %d\n", resultStartAt, resultLength);
return 0;
}
Start from the beginning of the string.
If you encounter an A, then mark the position and push it on a stack. After that, keep checking the characters sequentially until
1. If you encounter an A, update the A's position to current value.
2. If you encounter a C, push it onto the stack.
After you encounter a C, again keep checking the characters sequentially until,
1. If you encounter a D, erase the stack containing A and C and mark the score from A to D for this sub-sequence.
2. If you encounter an A, then start another Stack and mark this position as well.
2a. If now you encounter a C, then erase the earlier stacks and keep the most recent stack.
2b. If you encounter a D, then erase the older stack and mark the score and check if it is less than the current best score.
Keep doing this till you reach the end of the string.
The pseudo code can be something like:
Initialize stack = empty;
Initialize bestLength = mainString.size() + 1; // a large value for the subsequence.
Initialize currentLength = 0;
for ( int i = 0; i < mainString.size(); i++ ) {
if ( stack is empty ) {
if ( mainString[i] == 'A' ) {
start a new stack and push A on it.
mark the startPosition for this stack as i.
}
continue;
}
For each of the stacks ( there can be at most two stacks prevailing,
one of size 1 and other of size 0 ) {
if ( stack size == 1 ) // only A in it {
if ( mainString[i] == 'A' ) {
update the startPosition for this stack as i.
}
if ( mainString[i] == 'C' ) {
push C on to this stack.
}
} else if ( stack size == 2 ) // A & C in it {
if ( mainString[i] == 'C' ) {
if there is a stack with size 1, then delete this stack;// the other one dominates this stack.
}
if ( mainString[i] == 'D' ) {
mark the score from startPosition till i and update bestLength accordingly.
delete this stack.
}
}
}
}
I modified my previous suggestion using a single queue, now I believe this algorithm runs with O(N*m) time:
FindSequence(char[] sequenceList)
{
queue startSeqQueue;
int i = 0, k;
int minSequenceLength = sequenceList.length + 1;
int startIdx = -1, endIdx = -1;
for (i = 0; i < sequenceList.length - 2; i++)
{
if (sequenceList[i] == 'A')
{
startSeqQueue.queue(i);
}
}
while (startSeqQueue!=null)
{
i = startSeqQueue.enqueue();
k = i + 1;
while (sequenceList.length < k && sequenceList[k] != 'C')
if (sequenceList[i] == 'A') i = startSeqQueue.enqueue();
k++;
while (sequenceList.length < k && sequenceList[k] != 'D')
k++;
if (k < sequenceList.length && k > minSequenceLength > k - i + 1)
{
startIdx = i;
endIdx = j;
minSequenceLength = k - i + 1;
}
}
return startIdx & endIdx
}
My previous (O(1) memory) suggestion:
FindSequence(char[] sequenceList)
{
int i = 0, k;
int minSequenceLength = sequenceList.length + 1;
int startIdx = -1, endIdx = -1;
for (i = 0; i < sequenceList.length - 2; i++)
if (sequenceList[i] == 'A')
k = i+1;
while (sequenceList.length < k && sequenceList[k] != 'C')
k++;
while (sequenceList.length < k && sequenceList[k] != 'D')
k++;
if (k < sequenceList.length && k > minSequenceLength > k - i + 1)
{
startIdx = i;
endIdx = j;
minSequenceLength = k - i + 1;
}
return startIdx & endIdx;
}
Here's my version. It keeps track of possible candidates for an optimum solution. For each character in the hay, it checks whether this character is in sequence of each candidate. It then selectes the shortest candidate. Quite straightforward.
class ShortestSequenceFinder
{
public class Solution
{
public int StartIndex;
public int Length;
}
private class Candidate
{
public int StartIndex;
public int SearchIndex;
}
public Solution Execute(string hay, string needle)
{
var candidates = new List<Candidate>();
var result = new Solution() { Length = hay.Length + 1 };
for (int i = 0; i < hay.Length; i++)
{
char c = hay[i];
for (int j = candidates.Count - 1; j >= 0; j--)
{
if (c == needle[candidates[j].SearchIndex])
{
if (candidates[j].SearchIndex == needle.Length - 1)
{
int candidateLength = i - candidates[j].StartIndex;
if (candidateLength < result.Length)
{
result.Length = candidateLength;
result.StartIndex = candidates[j].StartIndex;
}
candidates.RemoveAt(j);
}
else
{
candidates[j].SearchIndex += 1;
}
}
}
if (c == needle[0])
candidates.Add(new Candidate { SearchIndex = 1, StartIndex = i });
}
return result;
}
}
It runs in O(n*m).
Here is my solution in Python. It returns the indexes assuming 0-indexed sequences. Therefore, for the given example it returns (9, 11) instead of (10, 12). Obviously it's easy to mutate this to return (10, 12) if you wish.
def solution(s, ss):
S, E = [], []
for i in xrange(len(s)):
if s[i] == ss[0]:
S.append(i)
if s[i] == ss[-1]:
E.append(i)
candidates = sorted([(start, end) for start in S for end in E
if start <= end and end - start >= len(ss) - 1],
lambda x,y: (x[1] - x[0]) - (y[1] - y[0]))
for cand in candidates:
i, j = cand[0], 0
while i <= cand[-1]:
if s[i] == ss[j]:
j += 1
i += 1
if j == len(ss):
return cand
Usage:
>>> from so import solution
>>> s = 'ADCBDABCDACD'
>>> solution(s, 'ACD')
(9, 11)
>>> solution(s, 'ADC')
(0, 2)
>>> solution(s, 'DCCD')
(1, 8)
>>> solution(s, s)
(0, 11)
>>> s = 'ABC'
>>> solution(s, 'B')
(1, 1)
>>> print solution(s, 'gibberish')
None
I think the time complexity is O(p log(p)) where p is the number of pairs of indexes in the sequence that refer to search_sequence[0] and search_sequence[-1] where the index for search_sequence[0] is less than the index forsearch_sequence[-1] because it sorts these p pairings using an O(n log n) algorithm. But then again, my substring iteration at the end could totally overshadow that sorting step. I'm not really sure.
It probably has a worst-case time complexity which is bounded by O(n*m) where n is the length of the sequence and m is the length of the search sequence, but at the moment I cannot think of an example worst-case.
Here is my O(m*n) algorithm in Java:
class ShortestWindowAlgorithm {
Multimap<Character, Integer> charToNeedleIdx; // Character -> indexes in needle, from rightmost to leftmost | Multimap is a class from Guava
int[] prefixesIdx; // prefixesIdx[i] -- rightmost index in the hay window that contains the shortest found prefix of needle[0..i]
int[] prefixesLengths; // prefixesLengths[i] -- shortest window containing needle[0..i]
public int shortestWindow(String hay, String needle) {
init(needle);
for (int i = 0; i < hay.length(); i++) {
for (int needleIdx : charToNeedleIdx.get(hay.charAt(i))) {
if (firstTimeAchievedPrefix(needleIdx) || foundShorterPrefix(needleIdx, i)) {
prefixesIdx[needleIdx] = i;
prefixesLengths[needleIdx] = getPrefixNewLength(needleIdx, i);
forgetOldPrefixes(needleIdx);
}
}
}
return prefixesLengths[prefixesLengths.length - 1];
}
private void init(String needle) {
charToNeedleIdx = ArrayListMultimap.create();
prefixesIdx = new int[needle.length()];
prefixesLengths = new int[needle.length()];
for (int i = needle.length() - 1; i >= 0; i--) {
charToNeedleIdx.put(needle.charAt(i), i);
prefixesIdx[i] = -1;
prefixesLengths[i] = -1;
}
}
private boolean firstTimeAchievedPrefix(int needleIdx) {
int shortestPrefixSoFar = prefixesLengths[needleIdx];
return shortestPrefixSoFar == -1 && (needleIdx == 0 || prefixesLengths[needleIdx - 1] != -1);
}
private boolean foundShorterPrefix(int needleIdx, int hayIdx) {
int shortestPrefixSoFar = prefixesLengths[needleIdx];
int newLength = getPrefixNewLength(needleIdx, hayIdx);
return newLength <= shortestPrefixSoFar;
}
private int getPrefixNewLength(int needleIdx, int hayIdx) {
return needleIdx == 0 ? 1 : (prefixesLengths[needleIdx - 1] + (hayIdx - prefixesIdx[needleIdx - 1]));
}
private void forgetOldPrefixes(int needleIdx) {
if (needleIdx > 0) {
prefixesLengths[needleIdx - 1] = -1;
prefixesIdx[needleIdx - 1] = -1;
}
}
}
It works on every input and also can handle repeated characters etc.
Here are some examples:
public class StackOverflow {
public static void main(String[] args) {
ShortestWindowAlgorithm algorithm = new ShortestWindowAlgorithm();
System.out.println(algorithm.shortestWindow("AXCXXCAXCXAXCXCXAXAXCXCXDXDXDXAXCXDXAXAXCD", "AACD")); // 6
System.out.println(algorithm.shortestWindow("ADCBDABCDACD", "ACD")); // 3
System.out.println(algorithm.shortestWindow("ADCBDABCD", "ACD")); // 4
}
I haven't read every answer here, but I don't think anyone has noticed that this is just a restricted version of local pairwise sequence alignment, in which we are only allowed to insert characters (and not delete or substitute them). As such it will be solved by a simplification of the Smith-Waterman algorithm that considers only 2 cases per vertex (arriving at the vertex either by matching a character exactly, or by inserting a character) rather than 3 cases. This algorithm is O(n^2).
Here's my solution. It follows one of the pattern matching solutions. Please comment/correct me if I'm wrong.
Given the input string as in the question
A D C B D A B C D A C D. Let's first compute the indices where A occurs. Assuming a zero based index this should be [0,5,9].
Now the pseudo code is as follows.
Store the indices of A in a list say *orders*.// orders=[0,5,9]
globalminStart, globalminEnd=0,localMinStart=0,localMinEnd=0;
for (index: orders)
{
int i =index;
Stack chars=new Stack();// to store the characters
i=localminStart;
while(i< length of input string)
{
if(str.charAt(i)=='C') // we've already seen A, so we look for C
st.push(str.charAt(i));
i++;
continue;
else if(str.charAt(i)=='D' and st.peek()=='C')
localminEnd=i; // we have a match! so assign value of i to len
i+=1;
break;
else if(str.charAt(i)=='A' )// seen the next A
break;
}
if (globalMinEnd-globalMinStart<localMinEnd-localMinStart)
{
globalMinEnd=localMinEnd;
globalMinStart=localMinStart;
}
}
return [globalMinstart,globalMinEnd]
}
P.S: this is pseudocode and a rough idea. Id be happy to correct it and understand if there's something wrong.
AFAIC Time complexity -O(n). Space complexity O(n)

Resources