Interpolation search out of range - algorithm

This is a piece of Wikipedia's sample implementation of interpolation search:
public int interpolationSearch(int[] sortedArray, int toFind){
// Returns index of toFind in sortedArray, or -1 if not found
int low = 0;
int high = sortedArray.length - 1;
int mid;
while (sortedArray[low] <= toFind && sortedArray[high] >= toFind) {
mid = low +
((toFind - sortedArray[low]) * (high - low)) /
(sortedArray[high] - sortedArray[low]); //out of range is possible here
if (sortedArray[mid] < toFind)
low = mid + 1;
else if (sortedArray[mid] > toFind)
// Repetition of the comparison code is forced by syntax limitations.
high = mid - 1;
else
return mid;
}
if (sortedArray[low] == toFind)
return low;
else
return -1; // Not found
}
Why is out of range possible there?
EDIT: added the whole code

Out of range is possible here if an integer overflow occurs.
To overcome this you can you float/double rather then a 32 bit integer.
Have a look at this,
What's wrong with this Interpolation search implementation?

Related

Develop an algorithm

I participated in a programming competition at my University. I solved all the questions except this one. Now I am practicing this question to improve my skills. But I can't figure out the algorithm. If there is any algorithm existing please update me. Or any similar algorithm is present then please tell me I will change it according to this question.
This is what I want to do.
The First line of input is the distance between two points.
After that, each subsequent line contains a pair of numbers indicating the length of cable and quantity of that cable. These cables are used to join the two points.
Input is terminated by 0 0
Output:
The output should contain a single integer representing the minimum number of joints possible to build the requested length of cableway. If no solution possible than print "No solution".
Sample Input
444
16 2
3 2
2 2
30 3
50 10
45 12
8 12
0 0
Sample Output
10
Thanks guys. I found a solution from "Perfect subset Sum" problem and then made a few changes in it. Here's the code.
#include <bits/stdc++.h>
using namespace std;
bool dp[100][100];
int sizeOfJoints = -1;
void display(const vector<int>& v)
{
if (sizeOfJoints == -1)
{
sizeOfJoints = v.size() - 1;
}
else if (v.size()< sizeOfJoints)
{
sizeOfJoints = v.size() - 1;
}
}
// A recursive function to print all subsets with the
// help of dp[][]. Vector p[] stores current subset.
void printSubsetsRec(int arr[], int i, int sum, vector<int>& p)
{
// If sum becomes 0
if (sum == 0)
{
display(p);
return;
}
if(i<=0 || sum<0)
return;
// If given sum can be achieved after ignoring
// current element.
if (dp[i-1][sum])
{
// Create a new vector to store path
//vector<int> b = p;
printSubsetsRec(arr, i-1, sum, p);
}
// If given sum can be achieved after considering
// current element.
if (sum >= arr[i-1] && dp[i-1][sum-arr[i-1]])
{
p.push_back(arr[i-1]);
printSubsetsRec(arr, i-1, sum-arr[i-1], p);
p.pop_back();
}
}
// all subsets of arr[0..n-1] with sum 0.
void printAllSubsets(int arr[], int n, int sum)
{
if (n == 0 || sum < 0)
return;
// If sum is 0, then answer is true
for (int i = 0; i <= n; i++)
dp[i][0] = true;
// If sum is not 0 and set is empty, then answer is false
for (int i = 1; i <= sum; i++)
dp[0][i] = false;
// Fill the subset table in botton up manner
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= sum; j++)
{
if(j<arr[i-1])
dp[i][j] = dp[i-1][j];
if (j >= arr[i-1])
dp[i][j] = dp[i-1][j] ||
dp[i - 1][j-arr[i-1]];
}
}
if (dp[n][sum] == false)
{
return;
}
// Now recursively traverse dp[][] to find all
// paths from dp[n-1][sum]
vector<int> p;
printSubsetsRec(arr, n, sum, p);
}
// Driver code
int main()
{
int input[2000];
int inputIndex = 0;
int i = 0;
int distance = 0;
cout<< "Enter Input: " <<endl;
cin>> distance;
while(true)
{
int temp1 = 0;
int temp2 = 0;
cin>> temp1;
cin>> temp2;
if (temp1 == 0 && temp2 == 0)
{
break;
}
for (i = 0; i < temp2; i++)
input[inputIndex++] = temp1;
}
cout<< "Processing output. Please wait: " <<endl;
printAllSubsets(input, inputIndex, distance);
if(sizeOfJoints != -1)
cout<<sizeOfJoints;
else
cout<<"No Solution Possible";
return 0;
}

Weird Outputs with Binary Search

So, this code has weird outputs when running on Command-Line with different outputs, I also get a segfault (core dumped) with some cases. I suspect it's to do with the min, max, mid bounds I have set. Please help me out as to what might be going wrong.
the code is searching based off two vectors of type class (Book) where all three elements ISBN,course, and type need to match for the counter to increment. We are searching for number of r in n.
int binary_search(std::vector<Book> n, std::vector<Book> r){
std::sort(n.begin(),n.end());
unsigned int mid;
int count = 0 ;
for (unsigned int i = 0; i < r.size(); i++) {
unsigned int min = 0 ;
unsigned int max = n.size() - 1;
while(max >= min) {
mid = (max + min) / (2);
if((n[mid].isbn == r[i].isbn) && (n[mid].course == r[i].course) && (n[mid].type == r[i].type)) {
count++;
break;
} else if(n[mid].isbn < r[i].isbn){
min = mid + 1;
} else{
max = mid - 1;
}
}
}
return count;
}

Find k in a k-sorted array

I'm trying to write a binary-search-like algorithm to find k in a k-sorted array. (It needs to be O(logn))
For example, k here is 3:
5, 6, 7, 1, 2, 3, 4
Here's my try in Java
public static int findk(int[] a) {
int low = 0;
int high = a.length-1;
while(low <= high) {
if(a[low] <= a[high])
return low;
int middle = (low+high)/2;
if(a[low] > a[middle])
high = middle-1;
else
low = middle+1;
}
return 0;
}
It works for some inputs but doesn't work for others. It should be really easy but I can't figure out what's wrong.
Even a hint will be nice!
You need to find the first element which is smaller than a[0]. So you need to compare against a[0].
public static int findk(int[] a) {
int low = 0;
int high = a.length - 1;
if (a[high] >= a[0]) // special case array completely sorted
return high + 1;
while(low < high) {
int middle = (low + high) / 2;
if(a[middle] < a[0])
high = middle;
else
low = middle + 1;
}
return low; // or high
}
You will get [0,6] on start, then [0,3], then [2,3] and finally [3,3].
The reason why we don't do high = middle - 1 is that this way we could end up in the k-values which we don't want.

Broken Merge Sort

Good morning, Stack Overflow. You guys helped me out on an earlier assignment, and I'm hoping to get a little help on this one.
It's a programming assignment relating to sorts, one part of which is to write a working implementation of merge sort.
I adapted my solution from the pseudocode the professor used in class, but I'm getting an annoying segfault at the indicated location.
This method is sorting an array of structs, with data_t defined as struct pointers.
The struct definition:
typedef struct {
int id;
int salary;
} employee_t;
typedef employee_t* data_t;
They're being sorted by salary, which is a randomly generated number from 40,000 to 90,000.
Here's the actual method
void merge_sort(data_t items[], size_t n)
{
if (n < 2)
return;
size_t mid = (n / 2);
data_t *left = malloc(sizeof(data_t) * mid);
data_t *right = malloc(sizeof(data_t) * (n - mid));
for (int y = 0; y < mid; y++)
{
left[y] = items[y];
}
for (int z = mid; z < n; z++)
{
right[z] = items[z];
}
merge_sort(left, mid);
merge_sort(right, (n - mid));
size_t l, r, i;
l = 0;
r = 0;
for (i = 0; i < (n - 1); i++)
{
if ((l < mid) && ((r >= (n - mid)) || ((left[l]->salary) <= (right[r]->salary))))
{
items[i] = left[l++];
}
else
{
items[i] = right[r++];
}
}
free(left);
free(right);
}
Note that I haven't made it as far as the end, so the array frees might be incorrectly located.
The segfault always occurs when I try to access right[r]->salary, so I'm assuming this is related to a null pointer, or similar. However, I'm extremely new to sorting, and I don't know exactly where to properly implement a check.
Any advice is appreciated greatly.
At first glance there's this fix:
for (int z = mid; z < n; z++)
{
right[z-mid] = items[z];
}

Old Top Coder riddle: Making a number by inserting +

I am thinking about this topcoder problem.
Given a string of digits, find the minimum number of additions required for the string to equal some target number. Each addition is the equivalent of inserting a plus sign somewhere into the string of digits. After all plus signs are inserted, evaluate the sum as usual.
For example, consider "303" and a target sum of 6. The best strategy is "3+03".
I would solve it with brute force as follows:
for each i in 0 to 9 // i -- number of plus signs to insert
for each combination c of i from 10
for each pos in c // we can just split the string w/o inserting plus signs
insert plus sign in position pos
evaluate the expression
if the expression value == given sum
return i
Does it make sense? Is it optimal from the performance point of view?
...
Well, now I see that a dynamic programming solution will be more efficient. However it is interesting if the presented solution makes sense anyway.
It's certainly not optimal. If, for example, you are given the string "1234567890" and the target is a three-digit number, you know that you have to split the string into at least four parts, so you need not check 0, 1, or 2 inserts. Also, the target limits the range of admissible insertion positions. Both points have small impact for short strings, but can make a huge difference for longer ones. However, I suspect there's a vastly better method, smells a bit of DP.
I haven't given it much thought yet, but if you scroll down you can see a link to the contest it was from, and from there you can see the solvers' solutions. Here's one in C#.
using System;
using System.Text;
using System.Text.RegularExpressions;
using System.Collections;
public class QuickSums {
public int minSums(string numbers, int sum) {
int[] arr = new int[numbers.Length];
for (int i = 0 ; i < arr.Length; i++)
arr[i] = 0;
int min = 15;
while (arr[arr.Length - 1] != 2)
{
arr[0]++;
for (int i = 0; i < arr.Length - 1; i++)
if (arr[i] == 2)
{
arr[i] = 0;
arr[i + 1]++;
}
String newString = "";
for (int i = 0; i < numbers.Length; i++)
{
newString+=numbers[i];
if (arr[i] == 1)
newString+="+";
}
String[] nums = newString.Split('+');
int sum1 = 0;
for (int i = 0; i < nums.Length; i++)
try
{
sum1 += Int32.Parse(nums[i]);
}
catch
{
}
if (sum == sum1 && nums.Length - 1 < min)
min = nums.Length - 1;
}
if (min == 15)
return -1;
return min;
}
}
Because input length is small (10) all possible ways (which can be found by a simple binary counter of length 10) is small (2^10 = 1024), so your algorithm is fast enough and returns valid result, and IMO there is no need to improve it.
In all until your solution works fine in time and memory and other given constrains, there is no need to do micro optimization. e.g this case as akappa offered can be solved with DP like DP in two-Partition problem, but when your algorithm is fast there is no need to do this and may be adding some big constant or making code unreadable.
I just offer parse digits of string one time (in array of length 10) to prevent from too many string parsing, and just use a*10^k + ... (Also you can calculate 10^k for k=0..9 in startup and save its value).
I think the problem is similar to Matrix Chain Multiplication problem where we have to put braces for least multiplication. Here braces represent '+'. So I think it could be solved by similar dp approach.. Will try to implement it.
dynamic programming :
public class QuickSums {
public static int req(int n, int[] digits, int sum) {
if (n == 0) {
if (sum == 0)
return 0;
else
return -1;
} else if (n == 1) {
if (sum == digits[0]) {
return 0;
} else {
return -1;
}
}
int deg = 1;
int red = 0;
int opt = 100000;
int split = -1;
for (int i=0; i<n;i++) {
red += digits[n-i-1] * deg;
int t = req(n-i-1,digits,sum - red);
if (t != -1 && t <= opt) {
opt = t;
split = i;
}
deg = deg*10;
}
if (opt == 100000)
return -1;
if (split == n-1)
return opt;
else
return opt + 1;
}
public static int solve (String digits,int sum) {
int [] dig = new int[digits.length()];
for (int i=0;i<digits.length();i++) {
dig[i] = digits.charAt(i) - 48;
}
return req(digits.length(), dig, sum);
}
public static void doit() {
String digits = "9230560001";
int sum = 71;
int result = solve(digits, sum);
System.out.println(result);
}
Seems to be too late .. but just read some comments and answers here which say no to dp approach . But it is a very straightforward dp similar to rod-cutting problem:
To get the essence:
int val[N][N];
int dp[N][T];
val[i][j]: numerical value of s[i..j] including both i and j
val[i][j] can be easily computed using dynamic programming approach in O(N^2) time
dp[i][j] : Minimum no of '+' symbols to be inserted in s[0..i] to get the required sum j
dp[i][j] = min( 1+dp[k][j-val[k+1][j]] ) over all k such that 0<=k<=i and val[k][j]>0
In simple terms , to compute dp[i][j] you assume the position k of last '+' symbol and then recur for s[0..k]

Resources