Dynamic prefix sum - algorithm

Is there any data structure which is able to return the prefix sum [1] of array, update an element, and insert/remove elements to the array, all in O(log n)?
[1] "prefix sum" is the sum of all elements from the first one up to given index
For example, given the array of non-negative integers 8 1 10 7 the prefix sum for first three elements is 19 (8 + 1 + 10). Updating the first element to 7, inserting 3 as the second element and removing the third one gives 7 3 10 7. Again, the prefix sum of first three elements would be 20.
For prefix sum and update, there is Fenwick tree. But I don't know how to handle the addition/removal in O(log n) with it.
On the other hand, there are several binary search trees such as Red-black tree, all of which handle the update/insert/remove in logarithmic time. But I don't know how to maintain the given ordering and do the prefix sum in O(log n).

A treap with implicit keys can perform all this operations in O(log n) time per query. The idea of implicit keys is pretty simple: we do not store any keys in nodes. Instead, we maintain subtrees' sizes for all nodes and find an appropriate position when we add or remove an element using this information.
Here is my implementation:
#include <iostream>
#include <memory>
struct Node {
int priority;
int val;
long long sum;
int size;
std::shared_ptr<Node> left;
std::shared_ptr<Node> right;
Node(long val):
priority(rand()), val(val), sum(val), size(1), left(), right() {}
};
// Returns the size of a node owned by t if it is not empty and 0 otherwise.
int getSize(std::shared_ptr<Node> t) {
if (!t)
return 0;
return t->size;
}
// Returns the sum of a node owned by t if it is not empty and 0 otherwise.
long long getSum(std::shared_ptr<Node> t) {
if (!t)
return 0;
return t->sum;
}
// Updates a node owned by t if it is not empty.
void update(std::shared_ptr<Node> t) {
if (t) {
t->size = 1 + getSize(t->left) + getSize(t->right);
t->sum = t->val + getSum(t->left) + getSum(t->right);
}
}
// Merges the nodes owned by L and R and returns the result.
std::shared_ptr<Node> merge(std::shared_ptr<Node> L,
std::shared_ptr<Node> R) {
if (!L || !R)
return L ? L : R;
if (L->priority > R->priority) {
L->right = merge(L->right, R);
update(L);
return L;
} else {
R->left = merge(L, R->left);
update(R);
return R;
}
}
// Splits a subtree rooted in t by pos.
std::pair<std::shared_ptr<Node>, std::shared_ptr<Node>> split(
std::shared_ptr<Node> t,
int pos, int add) {
if (!t)
return make_pair(std::shared_ptr<Node>(), std::shared_ptr<Node>());
int cur = getSize(t->left) + add;
std::pair<std::shared_ptr<Node>, std::shared_ptr<Node>> res;
if (pos <= cur) {
auto ret = split(t->left, pos, add);
t->left = ret.second;
res = make_pair(ret.first, t);
} else {
auto ret = split(t->right, pos, cur + 1);
t->right = ret.first;
res = make_pair(t, ret.second);
}
update(t);
return res;
}
// Returns a prefix sum of [0 ... pos]
long long getPrefixSum(std::shared_ptr<Node>& root, int pos) {
auto parts = split(root, pos + 1, 0);
long long res = getSum(parts.first);
root = merge(parts.first, parts.second);
return res;
}
// Adds a new element at a position pos with a value newValue.
// Indices are zero-based.
void addElement(std::shared_ptr<Node>& root, int pos, int newValue) {
auto parts = split(root, pos, 0);
std::shared_ptr<Node> newNode = std::make_shared<Node>(newValue);
auto temp = merge(parts.first, newNode);
root = merge(temp, parts.second);
}
// Removes an element at the given position pos.
// Indices are zero-based.
void removeElement(std::shared_ptr<Node>& root, int pos) {
auto parts1 = split(root, pos, 0);
auto parts2 = split(parts1.second, 1, 0);
root = merge(parts1.first, parts2.second);
}
int main() {
std::shared_ptr<Node> root;
int n;
std::cin >> n;
for (int i = 0; i < n; i++) {
std::string s;
std::cin >> s;
if (s == "add") {
int pos, val;
std::cin >> pos >> val;
addElement(root, pos, val);
} else if (s == "remove") {
int pos;
std::cin >> pos;
removeElement(root, pos);
} else {
int pos;
std::cin >> pos;
std::cout << getPrefixSum(root, pos) << std::endl;
}
}
return 0;
}

An idea: to modify an AVL tree. Additions and deletions are done by index. Every node keeps the count and the sum of each subtree to allow all operations in O(log n).
Proof-of-concept with add_node and update_node and prefix_sum implemented:
class Node:
def __init__(self, value):
self.value = value
self.left = None
self.right = None
self.left_height = 0
self.right_height = 0
self.left_count = 1
self.left_sum = value
self.right_count = 0
self.right_sum = 0
def set_value(self, value):
self.value = value
self.left_sum = self.left.left_sum + self.left.right_sum+self.value if self.left else self.value
def set_left(self, node):
self.left = node
self.left_height = max(node.left_height, node.right_height)+1 if node else 0
self.left_count = node.left_count + node.right_count+1 if node else 1
self.left_sum = node.left_sum + node.right_sum+self.value if node else self.value
def set_right(self, node):
self.right = node
self.right_height = max(node.left_height, node.right_height)+1 if node else 0
self.right_count = node.left_count + node.right_count if node else 0
self.right_sum = node.left_sum + node.right_sum if node else 0
def rotate_left(self):
b = self.right
self.set_right(b.left)
b.set_left(self)
return b
def rotate_right(self):
a = self.left
self.set_left(a.right)
a.set_right(self)
return a
def factor(self):
return self.right_height - self.left_height
def add_node(root, index, node):
if root is None: return node
if index < root.left_count:
root.set_left(add_node(root.left, index, node))
if root.factor() < -1:
if root.left.factor() > 0:
root.set_left(root.left.rotate_left())
return root.rotate_right()
else:
root.set_right(add_node(root.right, index-root.left_count, node))
if root.factor() > 1:
if root.right.factor() < 0:
root.set_right(root.right.rotate_right())
return root.rotate_left()
return root
def update_node(root, index, value):
if root is None: return root
if index+1 < root.left_count:
root.set_left(update_node(root.left, index, value))
elif index+1 > root.left_count:
root.set_right(update_node(root.right, index - root.left_count, value))
else:
root.set_value(value)
return root
def prefix_sum(root, index):
if root is None: return 0
if index+1 < root.left_count:
return prefix_sum(root.left, index)
else:
return root.left_sum + prefix_sum(root.right, index-root.left_count)
import random
tree = None
tree = add_node(tree, 0, Node(10))
tree = add_node(tree, 1, Node(40))
tree = add_node(tree, 1, Node(20))
tree = add_node(tree, 2, Node(70))
tree = update_node(tree, 2, 30)
print prefix_sum(tree, 0)
print prefix_sum(tree, 1)
print prefix_sum(tree, 2)
print prefix_sum(tree, 3)
print prefix_sum(tree, 4)

Related

Converging maze: Largest cycle

This question was asked in one interview and i am still hunting for the best solution.
You are given a maze with N cells. Each cell may have multiple entry points but not more than one exit
(ie. entry/exit points are unidirectional doors like valves).
The cells are named with an integer value from 0
to N-1.
You need to find the the length of the largest cycle in the maze. Return -1 if there are no cycles.
INPUT FORMAT
First line has the number of cells N
Second line has list of N values of the edge[] array. edge[i] contains the cell number that
can be reached from of cell ‘i’ in one step. edge[i] is -1 if the ‘i’th cell doesn’t have an exit.
OUTPUT FORMAT
length of the largest cycle.
Sample input:
23
4 4 1 4 13 8 8 8 0 8 14 9 15 11 -1 10 15 22 22 22 22 22 21
Sample output
6
I have already tried to do this with DFS to find all possible cycles and print the largest cycle size.
Please let me know if there is any better solution for the same.
Given a node in the graph, there's a unique maximal path starting from it (since there's at most one exit from any node). It may or may not cycle.
It's easy to find the eventual cycle length starting from a node: keep following exit nodes, recording nodes in a set along the path. Stop when you either find no exit node, or you're about to visit a previously visited node. If there's no exit node there's no cycle, and otherwise you can find the cycle length by starting at the previously visited node, and re-trace the cycle. [You could also use Floyd's algorithm here which would require O(1) rather than O(N) storage, but we're going to use O(N) storage anyway in the next step].
Using this, one can find the maximum cycle in O(N) time: repeat the above algorithm for each node in the graph, but cache results (storing -1 if there's no cycle found). You have to be careful to stop the cycle-finding above if you find a previously cached result along your path, and once you've found a result for a node, you must cache the result for all nodes along the path until you find a node who's result is already cached. The size of the largest cycle is the value of the largest cached value.
This is O(N) runtime: each edge (of which there's at most N) is followed at most 3 times in the graph, and the cache is updated exactly once for each node in the graph. It's uses O(N) additional storage.
public static int solution(int arr[])
{
ArrayList<Integer> sum = new ArrayList<>();
for(int i = 0; i < arr.length; i ++)
{
ArrayList<Integer> path = new ArrayList<>();
int j = i;
int tempSum = 0;
while(arr[j]<arr.length && arr[j]!=i && arr[j]!=-1 && !path.contains(j))
{
path.add(j);
tempSum+=j;
j=arr[j];
if(arr[j]==i)
{
tempSum+=j;
break;
}
}
if(j<arr.length && i == arr[j])
sum.add(tempSum);
}
if(sum.isEmpty())
return -1;
return Collections.max(sum);
}
Here is an implementation in JavaScript. I didn't use any fancy features of JavaScript, so the algorithm can be readily seen from the code. On the other hand, it does need ES6 support to run (forget IE):
function largestCycle(edges) {
var result, visitedFrom, startCell, cell, cells;
result = [];
visitedFrom = Array(edges.length).fill(-1);
for (startCell = 0; startCell < edges.length; startCell++) {
cells = [];
for (cell=startCell; cell>-1 && visitedFrom[cell]===-1; cell = edges[cell]) {
visitedFrom[cell] = startCell;
cells.push(cell);
}
if (cell > -1 && visitedFrom[cell] === startCell) {
cells = cells.slice(cells.indexOf(cell));
if (cells.length > result.length) result = cells;
}
}
return result;
}
// Snippet I/O
var input = document.querySelector('textarea');
var output = document.querySelector('span');
(input.oninput = function () {
// Get input as array of numbers
var edges = input.value.trim().split(/\s+/).map(Number);
// Apply algorithm
var cycle = largestCycle(edges);
// Output result
output.textContent = cycle.length + ': ' + JSON.stringify(cycle);
})(); // Execute also at page load
Input:<br>
<textarea style="width:100%">4 4 1 4 13 8 8 8 0 8 14 9 15 11 -1 10 15 22 22 22 22 22 21</textarea><br>
Greatest Cycle: <span></span>
This runs in O(n). Even though the outer loop has both a nested loop and an expression that iterates over an array (using slice and indexOf), these sub-iterations are only executed once per cell, so in total this is still O(n).
The function does not only return the cycle size, but also the array containing the list of cells that belong to that cycle. It is a small overhead, but allows to better verify the result.
Python implementation of the solution suggested by trincot.
Explanation:
iterate over each node
For each node use the indices to navigate to the next node. Eg(1st iteration : outer for loop)
from 0th index we can reach 4 , from 4th index we can reach 13 , and from 13th index we can reach 11, and so on till we reach the visited node again in our case 0,
viola , we have found the first cycle.
check if visitedFrom[cell] == startCell i.e. 0 add it to the result array.
repeat for next node (step1)
Code
def largestCycle(edges):
result = []
visitedFrom = [-1] * len(edges)
for startCell in range(0, len(edges)):
cells = []
cell = startCell
while cell > -1 and visitedFrom[cell] == -1:
visitedFrom[cell] = startCell
cells.append(cell)
cell = edges[cell]
if cell > -1 and visitedFrom[cell] == startCell:
cells_idx = cells.index(cell)
cells = cells[cells_idx:]
if len(cells) > len(result):
result = cells
return result,len(result)
size = 23
edges = [4, 4, 1, 4, 13, 8, 8, 8, 0, 8, 14, 9, 15, 11, -1, 10, 15, 22, 22, 22, 22, 22, 21]
largestCycle(edges)
Using Prims algorithm to Find max Cycle in the Node
n = int(input())
v = n
e = v+1
arr = [int(i) for i in input().split()]
graph = [[0 for _ in range(n)] for _ in range(n)]
for i in range(0, len(arr)):
graph[i][arr[i]] = 1
for i in graph:
print(i)
def min_ind(wieight, visied):
min_ = -1
ind = -1
for i in range(v):
if(wieight[i] > min_ and visied[i] == False):
min_ = wieight[i]
ind = i
return ind
def printPath(parent, i):
res = []
while(parent[i] != -1):
res.append(i)
i = parent[i]
res.append(i)
return res[::-1]
# Dijkstra
visited = [False for _ in range(v)]
wieight = [0 for _ in range(v)]
parent = [-1 for i in range(v)]
wieight[0] = 0
path = []
for _ in range(v):
u = min_ind(wieight, visited)
if(u == -1):
continue
visited[u] = True
for i in range(v):
if(graph[u][i] > 0 and visited[i] == False):
if(wieight[i] < graph[u][i]):
wieight[i] = graph[u][i]
parent[i] = u
maximum = 0
for i in range(0, len(wieight)):
print("No:", i, " Weight:", wieight[i], " Path:", end=" ")
path = (printPath(parent, i))
maximum = max(maximum, len(path))
print(path, end=" ")
print()
print("Longest Cycle: ", maximum)
here is the solution for the problem but input format is not actually the same.
Here is the input format:
test cases: N
size of array: M
array elements: 1<=a(i)<=M-1 where 0<=i<=M-1
index to which last index points: C
In this problem, we have to count the cells in the largest cycle, here is the code:
class countLargestCycleMaze {
static vertex[] cells;
static class vertex {
int name;
neighbor list;
public vertex(int v, neighbor nb) {
this.name = v;
this.list = nb;
}
}
static class neighbor {
int vnum;
neighbor next;
public neighbor(int v, neighbor nb) {
this.vnum = v;
this.next = nb;
}
}
static int dfs(int v, int m) {
neighbor tmp = cells[v].list;
int c = 0;
while (tmp.vnum != m)
tmp = cells[tmp.vnum].list;
tmp = cells[tmp.vnum].list;
while (tmp.vnum != m) {
tmp = cells[tmp.vnum].list;
c++;
}
return c;
}
public static void main(String[] args) throws java.lang.Exception {
try {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int i, j, n, m, c;
n = Integer.parseInt(br.readLine());
while (n-- > 0) {
m = Integer.parseInt(br.readLine());
StringTokenizer st = new StringTokenizer(br.readLine());
c = Integer.parseInt(br.readLine());
if (c == 0) {
System.out.println("0");
continue;
}
cells = new vertex[m + 1];
for (i = 0; i < m; i++) {
int num = Integer.parseInt(st.nextToken());
cells[i] = new vertex(num, null);
cells[i].list = new neighbor(num, cells[i].list);
}
cells[m] = new vertex(c, null);
cells[m].list = new neighbor(c, cells[m].list);
System.out.println(dfs(0, c));
}
} catch (Exception e) {}
}
}
public class LargestCycleInGraph {
public static int checkCycle(int []cell , int size , int start) {
Set<Integer> set = new HashSet<>();
set.add(start);
for(int i = start ;i< size;i++) {
if( !set.contains(cell[i]) && cell[i] != -1) {
set.add( cell[i] );
}
else return set.size() + 1; // 1 for again come to cycle node
}
return -1;
}
public static int findLargestCycle(int []cell , int size) {
int max = -1;
for(int i =0;i<size;i++) {
//if you want to find sum of largest cycle return "Set" rather than its size and check for max sum
int cyc = checkCycle(cell , size , i);
if(max < cyc)
max = cyc;
}
return max;
}
public static void main(String[] args) {
int size = 23;
int []cell = {4, 4, 1, 4, 13, 8, 8, 8, 0, 8, 14, 9, 15, 11, -1, 10, 15, 22, 22, 22, 22, 22, 21};
int largestCycle = findLargestCycle(cell , size);
System.out.println("Largest cycle Length " +largestCycle);
}
}
def main():
size = int(input())
cell = input().split()
for i in range(0, len(cell)):
cell[i] = int(cell[i])
m = -1
for i in range(0, 23):
if m < check_cycle(cell, i):
m = check_cycle(cell, i)
print("Largest cycle is made of", m, "nodes")
def check_cycle(cell, start):
i = start
if i in cell:
cycle = [i]
j = i
while 1:
for k in cycle:
if cycle.count(k) >= 2:
if cycle[0] == cycle[-1]:
return len(cycle)-1
else:
return 0
else:
cycle.append(cell[j])
j = cell[j]
else:
return 0
main()
Here is my attempt, to traverse each node of the graph:-
#include <stdio.h>
int findingLargestCycle(int noOfInputs, int *edges){
int largestCycle = 0;
for(int i=0; i<noOfInputs; i++){
int currentEdge = edges[i];
int count = currentEdge;
int nextEdge = edges[currentEdge];
int n = 0;
while(currentEdge != nextEdge && n<noOfInputs+1){
if(nextEdge == -1 || currentEdge == -1){
count = 0;
break;
}
if(nextEdge != currentEdge){
count += nextEdge;
}
nextEdge = edges[nextEdge];
n++;
}
if(count > largestCycle && n != noOfInputs+1){
largestCycle = count;
}
}
return largestCycle;
}
int main(){
int testCases;
scanf("%d", &testCases);
int numberOfInputs;
scanf("%d", &numberOfInputs);
int edges[numberOfInputs];
for(int i=0; i<numberOfInputs; i++){
scanf("%d", &edges[i]);
}
printf("%d", findingLargestCycle(numberOfInputs, &edges[0]));
}
O(n) time complexity solution each node is visited only after checking it's visited before or not, so each node is visited only once.
O(n) space complexity ([n]:stack space max + [2*n]:two map used max size)
To observe: there is always a unique path between two nodes(check with any test case), because of condition, only one exit from each node.
C++ code:
#include <iostream>
#include <vector>
#include <unordered_map>
using namespace std;
//res stores result
int res = 0;
//visit to check in before visiting the node, to stop repeat visiting
unordered_map<int,bool> visit;
void dfs(vector<int> & a, unordered_map<int,int> &mp, int i, int k){
if(visit.find(i) != visit.end())
return;
if(a[i] == -1){
visit[i] = true;
return;
}
if(mp.find(i) != mp.end()){
res = max(res, k-mp[i]);
visit[i] = true;
return;
}
mp[i] = k;
dfs(a, mp, a[i], k+1);
visit[i] = true;
}
int main() {
int n;
cin>>n;
vector<int> a(n,0);
for(int i=0;i<n;i++)
cin>>a[i];
for(int i=0;i<n;i++){
if(visit.find(i) == visit.end()){
unordered_map<int,int> mp;
dfs(a, mp, i, 0);
}
}
cout<<res<<endl;
return 0;
}
Solution in C++
#include <bits/stdc++.h>
using namespace std;
bool isCycle(vector<int> arr, int curr, vector<bool> &visited, vector<int> &path)
{
if (curr == -1)
{
return false;
}
if (visited[curr])
{
return true;
}
visited[curr] = true;
path.emplace_back(curr);
if (isCycle(arr, arr[curr], visited, path))
return true;
return false;
}
int largestSumCycle(vector<int> arr)
{
int n = arr.size();
int sum = INT_MIN;
vector<bool> visited(n, false);
for (int i = 0; i < n; i++)
{
visited[i] = true;
vector<int> path;
if (isCycle(arr, arr[i], visited, path))
sum = max(sum, accumulate(path.begin(), path.end(), 0));
visited[i] = false;
}
if (sum == INT_MIN)
return -1;
return sum;
}
This is a common question in interviews, in the same interview they asked this question also for the same details in question.
Q: find the NEAREST MEETING CELL (NMC)
INPUT : same as above + third line has 2 numbers whose nearest meeting cell is to be found.
SAMPLE INPUT
23
4 4 1 4 13 8 8 8 0 8 14 9 15 11 -1 10 15 22 22 22 22 22 21
9 2 (need to find out meeting point of 9 , 2 in the mesh/graph)
OUTPUT
4
CODE:
def main():
testCASES=int(input())
# testCASES=1
for case_number in range(testCASES):
meshsize=input()
mesh=input()
# mesh='4 4 1 4 13 8 8 8 0 8 14 9 15 11 -1 10 15 22 22 22 22 22 21'
det=input()
# det='9 2'
mesh=[int(x) for x in mesh.split()]
det=[int(x) for x in det.split()]
n1=det[0]
n2=det[1]
n1path=[]
n2path=[]
for i in range(len(mesh)):
if not n1path:
n1path.append(mesh[n1])
else:
n1path.append(mesh[n1path[i-1]])
if not n2path:
n2path.append(mesh[n2])
else:
n2path.append(mesh[n2path[i-1]])
nearestList=[]
try:
for x in n1path:
nearestList.append(n2path.index(x))
NEAREST_NODE=n2path[min(nearestList)]
except Exception as e:
NEAREST_NODE = -1
# print(n1path,n2path)
print(NEAREST_NODE)
main()
WORKING:
walks paths from given 2 points, and calculate first common point of n1path and n2path, by using min() function on indices of nearest list. naming is arbitary, but thats the core algo.
it can handle if cycles are present, and still return the first intersection point.
returns -1 if no matches are found.
This is one more variant of the problem, apart from the normal inpt, we're given two nodes, src and dest, and we have to output the node which is the closest to both src and dest.
Here's my solution to finding nearest cell from both src and dest
#include<bits/stdc++.h>
using namespace std;
//returns answer
int solution(vector<int> arr, int src, int dest){
// Two maps, visA for distance from src and visB for distance from dest
// They serve two purpose, if visA[x] == 0, that means we haven't reached that node yet,
// and if it holds any value, say d, that means it is d distance away from the particular node
map<int,int> visA,visB;
int start = arr[src];
int curr = 1;
set<int> s; // contains unique set of nodes to check at last
// iniitializing final nodes
for(auto &x: arr){
s.insert(x);
}
// traversing until we get to a cell where we've already reached
while(visA[start] == 0){
visA[start] = curr; // Marcking the distance
curr++;
start = arr[start];
if(start == -1){
break; // Getting out if we get to a node who is not pointing at any other node
}
}
start = arr[dest];
// Same logic as above but traversing from dest
while(visB[start] == 0){
visB[start] = curr;
curr++;
start = arr[start];
if(start == -1){
break;
}
}
// This is an array of two values, vp[i].first holds the sum of distance of vp[i].second from src and dest.
vector<pair<int,int>> vp;
for(auto &x: s){
if(visA[x] != 0 && visB[x] != 0){ // Checking if we ever got to that particular node from both src and dest or not
pair<int,int> p = {visA[x] + visB[x], x};
vp.push_back(p);
}
}
// sorting and finding the node with list sum of visA[} + visB[]
sort(vp.begin(), vp.end());
return vp[0].second;
}
int main(){
int n; cin>>n;
vector<int> v;
for(int i = 0; i<n; i++){
int a; cin>>a;
v.push_back(a);
}
int a,b; cin>>a>>b;
cout << (solution(v,a,b));
}
function largestCycle(edges) {
var result, visitedFrom, startCell, cell, cells;
result = [];
visitedFrom = Array(edges.length).fill(-1);
for (startCell = 0; startCell < edges.length; startCell++) {
cells = [];
for (cell=startCell; cell>-1 && visitedFrom[cell]===-1; cell = edges[cell]) {
visitedFrom[cell] = startCell;
cells.push(cell);
}
if (cell > -1 && visitedFrom[cell] === startCell) {
cells = cells.slice(cells.indexOf(cell));
if (cells.length > result.length) result = cells;
}
}
return result;
}
// Snippet I/O
var input = document.querySelector('textarea');
var output = document.querySelector('span');
(input.oninput = function () {
// Get input as array of numbers
var edges = input.value.trim().split(/\s+/).map(Number);
// Apply algorithm
var cycle = largestCycle(edges);
// Output result
output.textContent = cycle.length + ': ' + JSON.stringify(cycle);
})(); // Execute also at page load
Input:<br>
<textarea style="width:100%">4 4 1 4 13 8 8 8 0 8 14 9 15 11 -1 10 15 22 22 22 22 22 21</textarea><br>
Greatest Cycle: <span></span>

Find smallest number in Sorted Rotatable Array

I came across this question in one Interview. Please help me in getting the solution.
Question is:
You have sorted rotatable array, i. e. the array contains elements which are sorted and it can be rotated circularly, like if the elements in array are [5,6,10,19,20,29] then rotating first time array becomes [29,5,6,10,19,20] and on second time it becomes [20,29,5,6,10,19] and so on.
So you need to find the smallest element in the array at any point. You won’t be provided with number times array is rotated. Just given the rotated array elements and find out the smallest among them. In this case output should be 5.
Method 1:
You can do this in O(logN) time.
Use a modified binary search to find the point of rotation which is an index i such that arr[i] > arr[i+1].
Example:
[6,7,8,9,1,2,3,4,5]
^
i
The two sub-arrays (arr[1], arr[2], .., arr[i]) and (arr[i+1], arr[i+2], ..., arr[n]) are sorted.
The answer is min(arr[1], arr[i+1])
Method 2:
When you split the sorted, rotated array into two halves (arr[1],..,arr[mid]) and (arr[mid+1],..,arr[n]), one of them is always sorted and the other always has the min. We can directly use a modified binary search to keep searching in the unsorted half
// index of first element
l = 0
// index of last element.
h = arr.length - 1
// always restrict the search to the unsorted
// sub-array. The min is always there.
while (arr[l] > arr[h]) {
// find mid.
mid = (l + h)/2
// decide which sub-array to continue with.
if (arr[mid] > arr[h]) {
l = mid + 1
} else {
h = mid
}
}
// answer
return arr[l]
The above algorihtm fails if data element is repeated like {8,8,8,8,8} or {1,8,8,8,8} or {8,1,8,8,8} or {8,8,1,8,8} or {8,8,8,8,1}
// solution pasted below will work all test cases :)
//break the array in two subarray and search for pattern like a[mid]>a[mid+1]
// and return the min position
public static int smallestSearch(int[] array,int start,int end)
{
if(start==end)
return array.length;
int mid=(start+end)/2;
if(array[mid]>array[mid+1])
return min(mid+1,smallestSearch(array,start,mid),smallestSearch(array,mid+1,end));
else
return min(smallestSearch(array,start,mid),smallestSearch(array,mid+1,end));
}
public static int min(int a,int b)
{
if(a==b)
return a;
else if(a<b)
return a;
else
return b;
}
public static int min(int a,int b,int c)
{
if(a<c)
{
if(a<b)
{
return a;
}
else
{
return b;
}
}
else
{
if(b<c)
return b;
else
return c;
}
}
To Find the smallest number in the sorted rotated array:
using Binary search concept
public class RotatedSortedArrayWithoutDuplicates1 {
public static void main(String[] args) {
int[] a = { 4, 6, 8, 10, 34, 56, 78, 1, 3 };
System.out.println(findMin(a));
}
private static int findMin(int[] a) {
if (a.length == 0 || a == null) {
return -1;
}
int start = 0;
int last = a.length - 1;
while (start + 1 < last) {
int mid = start + (last - start) / 2;
int m = a[mid];
int s = a[start];
int l = a[last];
if (m > l) {
start = mid + 1;
}
if (m < l) {
last = mid;
} else {
last--;
}
} // while
if (a[start] > a[last]) {
return a[last];
} else {
return a[start];
}
}
}
But if you don't want to use Binary Search, then :
public class Abc {
public static void main(String[] args) {
int[] a = { 4, 5, 6, 7, 7, 8, 9, 1, 1, 2, 3, 3 };
System.out.println(findMin(a));
}
public static int findMin(int[] a) {
int min = a[a.length - 1];
for (int i = 0; i < a.length; i++) {
if (min > a[i]) {
min = a[i];
break;
}
}
return min;
}// findmin
}// end
Here is the code in Python:
def fix(a):
min = a[0]
for i in range(len(a)):
if(min > a[i]):
min = a[i]
break
return min
a = [2, 2,3,4,1,2]
print(fix(a))
My code is below with the algorithm as comments. Works even for the repeated elements.
//Find Min in Rotated Sorted Array
//Example: int array[10] = {7, 8, 9, 10, 11, 12, 3, 4, 5, 6};
// Min in the above array is 3
// Solution: Recursively search (Modified binary search) for the Pivot where is the smallest Element is present
// Algorithm:
// 1) Find the Mid of the Array
// 2) call the recursive function on segment of array in which there is a deviation in the order
// If (A[low] > A[mid]) array segment in which deviation in the order present is (low, mid)
// If (A[low] < A[mid]) array segment in which deviation in the order present is (mid + 1, high)
// Time Complexity: O(logn)
// Space Complexity: is of the recursive function stack that is being used
#define MIN(x,y) (x) <= (y) ? (x): (y)
int MininRotatedSortedArray(int A[], int low, int high)
{
if(low > high)
return -1;
if(low == high - 1)
return MIN(A[low], A[high]);
int mid = low + (high - low)/2;
if(A[low] > A[mid])
return MininRotatedSortedArray(A, low, mid);
else if(A[low] < A[mid])
return MininRotatedSortedArray(A, mid + 1, high);
else
return A[mid];
}
This can be done in O(1) time best case, O(n) time worst case, and O(lg n) time on average.
For a rotated sorted array, if the first element in the array is less than the last element in the array, then the sorted array is not rotated (or rotated 0 position). The minimum element is simply the first element.
If the middle element is less than the last element, then the minimum element is in [first, middle].
If the middle element is greater than the last element, then the minimum element is in [middle + 1, last].
If the middle element is equal to the last element, then there are two sub-cases:
the first element is larger than the last element, in which case the minimum element is in [first, middle + 1];
the first element is equal to the last element, in which case it is inconclusive to reject either half of the array. Reduce to linear search. For example, for arrays such as [5,5,5,1,5] and [5,1,5,5,5], it is impossible by just examining the first, last and middle element (since they are all equal) which half of the array the minimum element lies.
I wrote the following code in C++ to solve this problem, which should handle all cases (empty array, repeated elements).
template <typename Iterator>
Iterator rotated_min(Iterator begin, Iterator end)
{
while (begin != end)
{
if (*begin < *(end - 1))
{
return begin;
}
Iterator mid = begin + (end - 1 - begin) / 2;
if (*mid < *(end - 1))
{
end = mid + 1;
}
else if (*mid > *(end - 1))
{
begin = mid + 1;
}
else
{
if (*begin > *(end - 1))
{
end = mid + 1;
++begin;
}
else
{
//reduce to linear search
typename ::std::iterator_traits<Iterator>::value_type min_value = *begin;
Iterator min_element = begin;
for (Iterator i = begin + 1; i != end; ++i)
{
if (*i < min_value)
{
min_value = *i;
min_element = i;
}
}
return min_element;
}
}
}
return begin;
}
Find Min index in circular sorted array
Example : [7,8,9,1,2,3,4,5,6]
int findMinIndex(int []a, int start, int end)
{
int mid = (start + end)/2;
if (start - end == 1)
if(a[start] < a[end])
return start;
else
return end;
if (a[mid] > a[end]){
return findMinIndex(a,mid,end);
}
else{
return findMinIndex(a,start,mid);
}
return -1; //Not found
}
In case any one needs it.. My implementation in java..
takes care of sorted/unsorted ascending//descending order usecases..
drawback is it will still perform log n steps to find min value in a perfectly sorted set with no rotation.
http://ideone.com/fork/G3zMIb
/* package whatever; // don't place package name! */
import java.util.*;
import java.lang.*;
import java.io.*;
/* Name of the class has to be "Main" only if the class is public. */
class Ideone
{
public static void main (String[] args) throws java.lang.Exception
{
int [] a = {3,3,0,2,2,2,2,1,2,2,2,2,2,2,2,2,2};
System.out.println(recursiveSplit(a,0,a.length-1));
}
public static int findMin(int x, int y){
if(x<=y){
return x;
}else{
return y;
}
}
public static int recursiveSplit(int[] arr , int a , int b){
int mid = (int) Math.floor(a + (b-a)/2);
int h1_l = a;
int h1_u = mid;
int h2_l = mid+1;
int h2_u = b;
int x=0;
int y=0;
//single element
if(a==b){
return arr[a];
}
//adjacent positions
if(h1_u-h1_l==1){
x=findMin(arr[h1_u],arr[h1_l]);
}else{
//else split
x=recursiveSplit(arr,h1_l,h1_u);
}
if(h2_u-h2_l==1){
y=findMin(arr[h2_u],arr[h2_l]);
}else{
y=recursiveSplit(arr, h2_l,h2_u);
}
return findMin(x, y);
}
}
Errors/suggestions/failed usecases are welcomed
public int findMin(int[] num) {
return findMin(num, 0, num.length-1);
}
public int findMin(int[] num, int left, int right){
if(left==right) return num[left];
if(left+1==right) return Math.min(num[left], num[right]);
int mid = (left+right)/2;
if(num[mid]>num[right]){
return findMin(num,mid+1,right);
}else if(num[mid]<num[right]){
return findMin(num,left,mid);
}else{
if(num[mid]==num[left]){
return Math.min(findMin(num,left,mid), findMin(num,mid,right));
}else{
return findMin(num,left,mid);
}
}
}
The following algorithm takes log(n) time. Assuming the array has no duplicate.
public int findMin(int[] num) {
if(num.length == 0) return -1
int r = num.length-1, l = 0;
while(l<r){
if(num[l]<=num[r]) return num[l]; //when not rotated, return the left most value
int mid = (r+l)/2;
if(num[mid]<num[r]){
r = mid;
}else{
l = mid+1;
}
}
return num[l];
}
I did it using a slightly modified version of binary search. What I am doing here is I keep going left or right based on where the minimum could be. For example in an ascending array if the mid element is less than the left most element, its possible that the minimum is to the left. While recursing thru the array, I also keep track of the minimum. The recursion continues until the end and then the latest min is returned. This also works with repeated elements.
public static void main(String[] args) throws IOException {
int[] rotated = {6, 7, 8, 1, 2, 3, 4, 5};
int min = findMin(rotated);
System.out.println(min);//1
}
public static int findMin(int[] sorted) {
return findMinRecursively(sorted, sorted[0], 0, (sorted.length - 1));
}
private static int findMinRecursively(int[] sorted, int min, int leftIndex, int rightIndex) {
if (leftIndex > rightIndex) {
return min;
}
int midIndex = (leftIndex + rightIndex) / 2;
if (sorted[midIndex] < min) {
min = sorted[midIndex];
}
if (sorted[midIndex] < sorted[leftIndex]) {
return findMinRecursively(sorted, min, leftIndex, (midIndex - 1));
} else {
return findMinRecursively(sorted, min, (midIndex + 1), rightIndex);
}
}
Question : Find minimum in a sorted rotated array .
Solution 1 : Using Binary Search
class Test18 {
public static void main(String[] args) {
int[] a = { 5, 6, 7, 8, 9, 10, 1, 2, 3 };
System.out.println(findmin(a));
}
// find min in a sorted rotated array
private static int findmin(int[] a) {
int start = 0;
int last = a.length - 1;
while (start + 1 < last) {
int mid = start + (last - start) / 2;
if (a[mid] > a[last]) {
start = mid + 1;
}
if (a[mid] < a[last]) {
last = mid;
} else {
mid--;
}
} // while
if (a[start] > a[last]) {
return a[last];
} else {
return a[start];
}
}
}
def searchinrotatedarray(arr1,l,h):
if l>h:
return arr1[0]
if h==l:
return arr1[l]
mid=(l+h)//2
if mid<h and arr1[mid+1]<arr1[mid]:
return arr1[mid+1]
elif mid>l and arr1[mid-1]<arr1[mid]:
return arr1[mid]
elif arr1[mid]<arr1[h]:
return searchinrotatedarray(arr1,l,mid-1)
else:
return searchinrotatedarray(arr1,mid+1,h)
first if statement checks if even array is rotated at all. in that case first element is the min . if length of list is 1 then that element is min.
else if mid element is less than last element then continue to look in second half else look for the element in first half
//java program to find minimum element in a sorted array rotated
//about any pivot in O(log n) in worst case and O(1) in best case
class ArrayRotateMinimum {
public static void main(String str[]) {
// initialize with your sorted rotated array here
int array[] = { 9, 1, 2, 3, 4, 5, 6, 7, 8, };
System.out.println("Minimum element is: " + minimumElement(array));
}
static int minimumElement(int array[]) {
// variables to keep track of low and high indices
int low, mid, high;
// initializing variables with appropriate values
low = 0;
high = array.length - 1;
while (low < high) {
// mid is always defined to be the average of low and high
mid = (low + high) / 2;
if (array[low] > array[mid]) {
// for eg if array is of the form [9,1,2,4,5],
// then shift high to mid to reduce array size by half
// while keeping minimum element between low and high
high = mid;
} else if (array[mid] > array[high]) {
// this condition deals with the end case when the final two
// elements in the array are of the form [9,1] during the
// last iteration of the while loop
if (low == mid) {
return array[high];
}
// for eg if array is of the form [4,5,9,1,2],
// then shift low to mid to reduce array size by half
// while keeping minimum element between low and high
low = mid;
} else {
// the array has not been rotated at all
// hence the first element happens to be the smallest element
return array[low];
}
}
//return first element in case array size is just 1
return array[0];
}
}
This is my pythonic solution using recursion:
Time complexity is O(log(n)) & Space complexity: O(1)
class Solution(object):
def findMin(self, nums):
left = 0
right = len(nums) -1
mid = len(nums) // 2
if len(nums) == 0:
return -1
if len(nums) == 1:
return nums[left]
if len(nums) == 2:
return min(nums[left], nums[right])
if nums[left] < nums[right]:
return nums[left]
elif nums[mid] > nums[left]:
return self.findMin(nums[mid + 1: ])
elif nums[mid] < nums[left]:
return self.findMin(nums[: mid + 1])
Here is a very simple answer, it will work for all test cases:
int a[] = {5,6,7,1,2,3,4};
int a[] = {1,2,3};
int a[] = {3,2,1};
int a[] = {3,1,2};
int a[] = {2,2,2,2};
public class FindSmallestNumberInSortedRotatedArray {
public static void main(String[] args) {
int a[] = { 4, 5, 6, 7, 1, 2, 3 };
int j = a.length - 1;
int i = 0;
while (i < j) {
int m = (i + j) / 2;
if (a[m] < a[m + 1] && a[m] < a[m - 1]) {
System.out.println(a[m] + "is smallest element ");
break;
} else if (a[m] > a[m + 1] && a[m - 1] > a[m + 1]) {
i = m + 1;
} else {
j = m - 1;
}
}
if (i == j)
System.out.println(a[i] + " is smallest element");
}
Solution for both array with duplicate and not, with the recursive binary search approach.
Unique array
var min = (A, l, h) => {
if(l >= h) return A[l];
let m = Math.floor((l + h) / 2);
// as its unique
if(A[m] > A[h]) {
// go towards right as last item is small than mid
return min(A, m + 1, h);
} else if(A[m] > A[m - 1]) {
// go towards left as prev item is smaller than current
return min(A, l, m - 1);
} else {
// right and left is greater than current
return A[m];
}
}
/**
* #param {number[]} nums
* #return {number}
*/
var findMin = function(nums) {
// If array is rotated nums.length time or same as it is
if(nums[0] < nums[nums.length - 1]) return nums[0];
return min(nums, 0, nums.length - 1);
};
Array with duplicates
var min = (A, l, h) => {
if(l >= h) return A[l];
// traverse from left "and right" to avoid duplicates in the end
while(A[l] == A[l+1]) {
l++;
}
let m = Math.floor((l + h) / 2);
// as its unique
if(A[m] > A[h]) {
// go towards right as last item is small than mid
return min(A, m + 1, h);
} else if(A[m] >= A[m - 1]) {
// go towards left as prev item is smaller than current
return min(A, l, m - 1);
} else {
// right and left is greater than current
return A[m];
}
}
/**
* #param {number[]} nums
* #return {number}
*/
var findMin = function(nums) {
// If array is rotated nums.length time or same as it is
if(nums[0] < nums[nums.length - 1]) return nums[0];
return min(nums, 0, nums.length - 1);
};

Help with algorithm problem from SPOJ

I thought it would be a fun problem: Prime Path
But...It is hard for me.
My only idea is "To do something with knapsack problem".. and no other ideas.
Could You track me for good way?
It's not for any challenge or University homework. I just want to learn something.
_
Ok, but firstly, how to find this prime numbers? Do i need to find all 4digit prime numbers, add it to graph?
For now i have generating all prime numbers.
http://pastebin.com/wbhRNRHQ
Could You give me sample code to declare graph build on neighbour list?
Seems like a straightforward graph path finding problem.
Take all 4 digit primes as the vertices. Connect two with an edge, if we can go from one to the other.
Now given two, you need to find the shortest path between them, in the graph we just formed. A simple BFS (breadth-first-search) should do for that.
For programming contests with time limits, you could even hardcode every possible prime pair path and get close to zero running time!
Build a graph where the nodes are all the 4 digit prime numbers, and there are arcs everywhere two numbers have three digits in common. From there, it's a basic graph traversal to find the lowest-cost path from one node to another.
I came across a similar question where I had to convert one 4 digit prime number 1033 to another 4 digit prime number 3739 in minimum number of steps. I was able to solve the problem, it might not be efficient but here is the working code for the same.
Below code has been written in Java
import java.util.*;
public class PrimeNumberProblem {
public static void main(String... args) {
System.out.println("Minimum number of steps required for converting 1033 to 3739 are = "
+ getMinSteps(1033, 3739));
}
public static int getMinSteps(int a, int b) {
if (a == b)
return 0;
List<Integer> primes = new ArrayList<>();
// get all the 4 digit prime numbers
primes = getPrimeNumbers();
// consists of graph with vertices as all the prime numbers
Graph graph = addNumbersToGraph(primes);
// adding edges to the graph vertices
Graph finalGraph = addWeightToGraph(graph);
// min number of steps required
int result = findShortestRoute(finalGraph.getVertex(a), finalGraph.getVertex(b));
return result;
}
private static int findShortestRoute(Vertex source, Vertex dest) {
if (source.getVertexValue() == dest.getVertexValue())
return 0;
// step 1 Initialize the queue. Also Map to store path
Queue<Vertex> visitedQueue = new LinkedList<>();
Map<Vertex, Vertex> currentPrevMap = new HashMap<Vertex, Vertex>();
// step 2 start from visiting S (starting node), and mark it visited, add to queue
Map<Integer, Boolean> visited = new HashMap<Integer, Boolean>();
visited.put(source.getVertexValue(), true);
visitedQueue.add(source);
int level = 0;
// step 3 Repeat until queue is empty
while (!visitedQueue.isEmpty()) {
// step 4 remove from queue
Vertex current = visitedQueue.remove();
if (current.getVertexValue() == dest.getVertexValue()) {
printPath(source, dest, currentPrevMap);
return level;
} else if (current.getAdjacentVertices().size() > 0) {
level++;
}
// step 5 add each of the unvisited neighbour and mark visited
for (Vertex adjacentVertex : current.getAdjacentVertices()) {
Integer value = adjacentVertex.getVertexValue();
if (value == dest.getVertexValue()) {
currentPrevMap.put(adjacentVertex, current);
printPath(source, dest, currentPrevMap);
return level;
}
if (visited.get(value) == null) {
currentPrevMap.put(adjacentVertex, current);
// mark visited and enqueue it
visited.put(value, true);
visitedQueue.add(adjacentVertex);
}
}
}
// not found
System.out.println("Dest vertex not found");
return -1;
}
private static void printPath(Vertex source, Vertex dest, Map<Vertex, Vertex> currentPrevMap) {
Vertex node = dest;
System.out.println("Reverse Path from source: " + source.getVertexValue() + " to dest: "
+ dest.getVertexValue());
while (node != source) {
System.out.println(node.getVertexValue());
node = currentPrevMap.get(node);
}
System.out.println(source.getVertexValue());
}
private static Graph addWeightToGraph(Graph graph) {
List<Vertex> vertices = graph.getAllVertices();
for (Vertex i : vertices) {
for (Vertex j : vertices) {
if (i.equals(j))
continue;
if (distance(i, j) == 1) {
i.getAdjacentVertices().add(j);
// i.addEdge(new Edge(i, j, 1));
}
}
}
return graph;
}
private static int distance(Vertex source, Vertex dest) {
if (source.getVertexValue() == dest.getVertexValue()) {
return 0;
}
char[] numA = extractIntegers(source.getVertexValue());
char[] numB = extractIntegers(dest.getVertexValue());
int len1 = numA.length;
int tracker = 0;
for (int i = 0; i < len1; i++) {
if (numA[i] != numB[i]) {
numA[i] = numB[i];
tracker++;
String sA = String.copyValueOf(numA);
String sB = String.copyValueOf(numB);
// if we have reached destination
if (Integer.parseInt(sA) == Integer.parseInt(sB)) {
return tracker;
}
}
}
return tracker;
}
private static char[] extractIntegers(int i) {
char[] arr = Integer.toString(i).toCharArray();
return arr;
}
private static Graph addNumbersToGraph(List<Integer> primes) {
Graph g = new Graph();
for (Integer prime : primes) {
g.addVertex(new Vertex(prime));
}
return g;
}
private static List<Integer> getPrimeNumbers() {
List<Integer> fourDigitPrimes = new ArrayList<>();
fourDigitPrimes.add(1033);
fourDigitPrimes.add(1733);
fourDigitPrimes.add(3733);
fourDigitPrimes.add(3739);
// for (int i = 1000; i < 9999; i++) {
// if (isPrime(i))
// fourDigitPrimes.add(i);
// }
return fourDigitPrimes;
}
private static boolean isPrime(int i) {
for (int k = 2; k < Math.sqrt(i); k++) {
if (i % k == 0)
return false;
}
return true;
}
}
class Graph {
public List<Vertex> vertexList = new ArrayList<Vertex>();
public void addVertex(Vertex V) {
vertexList.add(V);
}
public List getAllAdjacentNodes(Vertex V) {
return V.getAdjacentVertices();
}
public List getAllVertices() {
return vertexList;
}
public Vertex getVertex(int val) {
Iterator<Vertex> keys = vertexList.iterator();
while (keys.hasNext()) {
Vertex v = keys.next();
if (v.getVertexValue() == val)
return v;
}
return null;
}
}
class Vertex {
int value;
private List<Vertex> adjacentVertices = new ArrayList<Vertex>();
public Vertex(int v) {
this.value = v;
}
public List<Vertex> getAdjacentVertices() {
return adjacentVertices;
}
public int getVertexValue() {
return value;
}
#Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
Vertex vertex = (Vertex) o;
return value == vertex.value;
}
#Override
public int hashCode() {
return value;
}
}
Look into "breadth-first search". Also worth bearing in mind here that the problem can be approached "from both ends" simultaneously (a chain from numbers X to Y can be reversed to get Y to X, and you can exploit this). Precalculating primes will avoid much computation along the way.
I'd run a BFS using probable prime testing, which would work relatively well with only 4 digit numbers. With only 4 digits, also, you may want to use more exacting methods to produce all primes to compare against for faster prime checking.
Could You give me sample code to
declare graph build on neighbour list?
here is a sample code for breadth first search
public static final int MAX = 10000;
boolean[] prime = new boolean[MAX];
int[] dist = new int[MAX];
//get digit i [1 to 4] in num
public int getDigit(int num,int i){
return num % ((int)Math.pow(10, i)) / ((int) Math.pow(10, i-1));
}
//set digit i to d
public int setDigit(int num,int i,int d){
return (num - getDigit(num, i)*(int)Math.pow(10, i-1)) + d * (int)Math.pow(10,i-1);
}
public int bfs(int start,int end){
Queue<Integer> q = new LinkedList<Integer>();
q.add(start);
HashSet<Integer> visited = new HashSet<Integer>();
visited.add(start);
dist[start] = 0;
int x,y,d = 0;
while (q.size() > 0){
x = q.poll();
d = dist[x];
if (x == end) return d;
for (int i = 1; i < 5; i++) {
//digit number i
for (int j = 0; j < 10; j++) {
//avoid setting last digit
if (j == 0 && i == 4) continue;
//set digit number i to j
y = setDigit(x, i, j);
if (prime[y] && y != x && !visited.contains(y)){
q.add(y);
visited.add(y);
dist[y] = d + 1;
}
}
}
}
return -1;
}
Here is my solution using BFS and I have already saved all 4 digit prime numbers into an array as there is no need to write a function to calculate the prime numbers. I hope it helps
#include<stdio.h>
int hash[10000];
int a,b,ans,level,new_num,count;
int prime[] = {1009,1013,1019,1021,1031,1033,1039,1049,1051,1061,1063,1069,1087,1091,1093,1097,1103,1109,1117,1123,1129,1151,1153,1163,1171,1181,1187,1193,1201,1213,1217,1223,1229,1231,1237,1249,1259,1277,1279,1283,1289,1291,1297,1301,1303,1307,1319,1321,1327,1361,1367,1373,1381,1399,1409,1423,1427,1429,1433,1439,1447,1451,1453,1459,1471,1481,1483,1487,1489,1493,1499,1511,1523,1531,1543,1549,1553,1559,1567,1571,1579,1583,1597,1601,1607,1609,1613,1619,1621,1627,1637,1657,1663,1667,1669,1693,1697,1699,1709,1721,1723,1733,1741,1747,1753,1759,1777,1783,1787,1789,1801,1811,1823,1831,1847,1861,1867,1871,1873,1877,1879,1889,1901,1907,1913,1931,1933,1949,1951,1973,1979,1987,1993,1997,1999,2003,2011,2017,2027,2029,2039,2053,2063,2069,2081,2083,2087,2089,2099,2111,2113,2129,2131,2137,2141,2143,2153,2161,2179,2203,2207,2213,2221,2237,2239,2243,2251,2267,2269,2273,2281,2287,2293,2297,2309,2311,2333,2339,2341,2347,2351,2357,2371,2377,2381,2383,2389,2393,2399,2411,2417,2423,2437,2441,2447,2459,2467,2473,2477,2503,2521,2531,2539,2543,2549,2551,2557,2579,2591,2593,2609,2617,2621,2633,2647,2657,2659,2663,2671,2677,2683,2687,2689,2693,2699,2707,2711,2713,2719,2729,2731,2741,2749,2753,2767,2777,2789,2791,2797,2801,2803,2819,2833,2837,2843,2851,2857,2861,2879,2887,2897,2903,2909,2917,2927,2939,2953,2957,2963,2969,2971,2999,3001,3011,3019,3023,3037,3041,3049,3061,3067,3079,3083,3089,3109,3119,3121,3137,3163,3167,3169,3181,3187,3191,3203,3209,3217,3221,3229,3251,3253,3257,3259,3271,3299,3301,3307,3313,3319,3323,3329,3331,3343,3347,3359,3361,3371,3373,3389,3391,3407,3413,3433,3449,3457,3461,3463,3467,3469,3491,3499,3511,3517,3527,3529,3533,3539,3541,3547,3557,3559,3571,3581,3583,3593,3607,3613,3617,3623,3631,3637,3643,3659,3671,3673,3677,3691,3697,3701,3709,3719,3727,3733,3739,3761,3767,3769,3779,3793,3797,3803,3821,3823,3833,3847,3851,3853,3863,3877,3881,3889,3907,3911,3917,3919,3923,3929,3931,3943,3947,3967,3989,4001,4003,4007,4013,4019,4021,4027,4049,4051,4057,4073,4079,4091,4093,4099,4111,4127,4129,4133,4139,4153,4157,4159,4177,4201,4211,4217,4219,4229,4231,4241,4243,4253,4259,4261,4271,4273,4283,4289,4297,4327,4337,4339,4349,4357,4363,4373,4391,4397,4409,4421,4423,4441,4447,4451,4457,4463,4481,4483,4493,4507,4513,4517,4519,4523,4547,4549,4561,4567,4583,4591,4597,4603,4621,4637,4639,4643,4649,4651,4657,4663,4673,4679,4691,4703,4721,4723,4729,4733,4751,4759,4783,4787,4789,4793,4799,4801,4813,4817,4831,4861,4871,4877,4889,4903,4909,4919,4931,4933,4937,4943,4951,4957,4967,4969,4973,4987,4993,4999,5003,5009,5011,5021,5023,5039,5051,5059,5077,5081,5087,5099,5101,5107,5113,5119,5147,5153,5167,5171,5179,5189,5197,5209,5227,5231,5233,5237,5261,5273,5279,5281,5297,5303,5309,5323,5333,5347,5351,5381,5387,5393,5399,5407,5413,5417,5419,5431,5437,5441,5443,5449,5471,5477,5479,5483,5501,5503,5507,5519,5521,5527,5531,5557,5563,5569,5573,5581,5591,5623,5639,5641,5647,5651,5653,5657,5659,5669,5683,5689,5693,5701,5711,5717,5737,5741,5743,5749,5779,5783,5791,5801,5807,5813,5821,5827,5839,5843,5849,5851,5857,5861,5867,5869,5879,5881,5897,5903,5923,5927,5939,5953,5981,5987,6007,6011,6029,6037,6043,6047,6053,6067,6073,6079,6089,6091,6101,6113,6121,6131,6133,6143,6151,6163,6173,6197,6199,6203,6211,6217,6221,6229,6247,6257,6263,6269,6271,6277,6287,6299,6301,6311,6317,6323,6329,6337,6343,6353,6359,6361,6367,6373,6379,6389,6397,6421,6427,6449,6451,6469,6473,6481,6491,6521,6529,6547,6551,6553,6563,6569,6571,6577,6581,6599,6607,6619,6637,6653,6659,6661,6673,6679,6689,6691,6701,6703,6709,6719,6733,6737,6761,6763,6779,6781,6791,6793,6803,6823,6827,6829,6833,6841,6857,6863,6869,6871,6883,6899,6907,6911,6917,6947,6949,6959,6961,6967,6971,6977,6983,6991,6997,7001,7013,7019,7027,7039,7043,7057,7069,7079,7103,7109,7121,7127,7129,7151,7159,7177,7187,7193,7207,7211,7213,7219,7229,7237,7243,7247,7253,7283,7297,7307,7309,7321,7331,7333,7349,7351,7369,7393,7411,7417,7433,7451,7457,7459,7477,7481,7487,7489,7499,7507,7517,7523,7529,7537,7541,7547,7549,7559,7561,7573,7577,7583,7589,7591,7603,7607,7621,7639,7643,7649,7669,7673,7681,7687,7691,7699,7703,7717,7723,7727,7741,7753,7757,7759,7789,7793,7817,7823,7829,7841,7853,7867,7873,7877,7879,7883,7901,7907,7919,7927,7933,7937,7949,7951,7963,7993,8009,8011,8017,8039,8053,8059,8069,8081,8087,8089,8093,8101,8111,8117,8123,8147,8161,8167,8171,8179,8191,8209,8219,8221,8231,8233,8237,8243,8263,8269,8273,8287,8291,8293,8297,8311,8317,8329,8353,8363,8369,8377,8387,8389,8419,8423,8429,8431,8443,8447,8461,8467,8501,8513,8521,8527,8537,8539,8543,8563,8573,8581,8597,8599,8609,8623,8627,8629,8641,8647,8663,8669,8677,8681,8689,8693,8699,8707,8713,8719,8731,8737,8741,8747,8753,8761,8779,8783,8803,8807,8819,8821,8831,8837,8839,8849,8861,8863,8867,8887,8893,8923,8929,8933,8941,8951,8963,8969,8971,8999,9001,9007,9011,9013,9029,9041,9043,9049,9059,9067,9091,9103,9109,9127,9133,9137,9151,9157,9161,9173,9181,9187,9199,9203,9209,9221,9227,9239,9241,9257,9277,9281,9283,9293,9311,9319,9323,9337,9341,9343,9349,9371,9377,9391,9397,9403,9413,9419,9421,9431,9433,9437,9439,9461,9463,9467,9473,9479,9491,9497,9511,9521,9533,9539,9547,9551,9587,9601,9613,9619,9623,9629,9631,9643,9649,9661,9677,9679,9689,9697,9719,9721,9733,9739,9743,9749,9767,9769,9781,9787,9791,9803,9811,9817,9829,9833,9839,9851,9857,9859,9871,9883,9887,9901,9907,9923,9929,9931,9941,9949,9967,9973};
int size = sizeof(prime)/sizeof(prime[0]);
int bfs(int,int);
typedef struct q{
int x, c;
} queue;
queue qq[10000];
int isprime(int x)
{
int l,r,m;
l=m=0; r=size-1;
while (l <= r)
{
int m = l + (r-l)/2;
if (prime[m] == x)
return 1;
if (prime[m] < x)
l = m + 1;
else
r = m - 1;
}
return 0;
}
int bfs(int num1,int num2)
{
int i,j,k,p,q,n;
new_num=p=q=0;
i=0;
j=1;
qq[i].x = num1;
qq[i].c = 0;
hash[num1] = 1;
while(i!=j)
{ n = qq[i].x;
level = qq[i].c;
if(n==num2)
{
count = level;
return count;
}
level++;
p = n%1000;
for(k=1;k<10;k++)
{ new_num = (k*1000)+ p;
if(isprime(new_num)&&(new_num!=n)&&(!hash[new_num]))
{
hash[new_num] = 1;
qq[j].x = new_num;
qq[j].c = level;
j++;
}}
p=q=new_num=0;
p = n/1000;
q = n%100;
for(k=0;k<10;k++)
{ new_num = (p*1000)+k*100+q;
if(isprime(new_num)&&(new_num!=n)&&(!hash[new_num]))
{
hash[new_num] = 1;
qq[j].x = new_num;
qq[j].c = level;
j++;
}}
p=q=new_num=0;
p = n/100;
q = n%10;
for(k=0;k<10;k++)
{ new_num = (p*100)+k*10+q;
if(isprime(new_num)&&(new_num!=n)&&(!hash[new_num]))
{
hash[new_num] = 1;
qq[j].x = new_num;
qq[j].c = level;
j++;
}}
p=q=new_num=0;
p = n/10;
for(k=0;k<10;k++)
{ new_num = (p*10)+k;
if(isprime(new_num)&&(new_num!=n)&&(!hash[new_num]))
{
hash[new_num] = 1;
qq[j].x = new_num;
qq[j].c = level;
j++;
}}
p=q=new_num=0;
i++;
}
return -1;}
int main()
{
int v,tc;
setbuf(stdout,NULL);
scanf("%d",&tc);
for(v=1;v<=tc;v++)
{ int i,j;
a=b=ans=level=new_num=count=0;
for(i=0;i<10000;i++)
{qq[i].x=0;
qq[i].c=0;
hash[i]=0;}
scanf("%d%d",&a,&b);
if(a==b)
{ ans = 0;}
else
{ ans = bfs(a,b);}
printf("Case #%d\n", v);
if(ans==-1)
{
printf("Impossible\n");
}
else
{printf("%d\n",ans);}
}
return 0;
}
My Python solution using BFS:
import queue
# Class to represent a graph
class Graph:
def __init__(self, V):
self.V = V # No. of vertices
self.prime_list = [[] for i in range(V)]
# function to add an edge to graph
def addedge(self, V1, V2):
self.prime_list[V1].append(V2)
self.prime_list[V2].append(V1)
def bfs(self, in1, in2):
visited = [0] * self.V
que = queue.Queue()
visited[in1] = 1
que.put(in1)
while not que.empty():
prime_index = que.get()
i = 0
while i < len(self.prime_list[prime_index]):
if not visited[self.prime_list[prime_index][i]]:
visited[self.prime_list[prime_index][i]] = visited[prime_index] + 1
que.put(self.prime_list[prime_index][i])
if self.prime_list[prime_index][i] == in2:
return visited[self.prime_list[prime_index][i]] - 1
i += 1
# // Finding all 4 digit prime numbers
def SieveOfEratosthenes(v):
# Create a boolean array "prime[0..n]" and initialize all entries it as true. A value in prime[i] will be
# finally be false if i is Not a prime, else true.
n = 9999
prime = [True] * (n + 1)
p = 2
while p * p <= 9999:
if prime[p]:
i = p * p
while i <= 9999:
prime[i] = False
i = i + p
p = p + 1
# v = []
for i in range(1000, n + 1):
if prime[i]:
v.append(i)
return v
def compare(a, b):
diff = 0
while a:
if a % 10 != b % 10:
diff += 1
a //= 10
b //= 10
# If the numbers differ only by a single # digit return true else false
if diff > 1:
return False
return True
def shortestPath(num1, num2):
# Generate all 4 digit
pset = []
SieveOfEratosthenes(pset)
# Create a graph where node numbers # are indexes in pset[] and there is
# an edge between two nodes only if # they differ by single digit.
g = Graph(len(pset))
for i in range(len(pset)):
for j in range(i + 1, len(pset)):
if compare(pset[i], pset[j]):
g.addedge(i, j)
# Since graph nodes represent indexes # of numbers in pset[], we find indexes of num1 and num2.
in1, in2 = None, None
for j in range(len(pset)):
if pset[j] == num1:
in1 = j
for j in range(len(pset)):
if pset[j] == num2:
in2 = j
return g.bfs(in1, in2)
# Driver code
if __name__ == '__main__':
num1 = 1033
num2 = 8179
print(shortestPath(num1, num2))

Minimum window width in string x that contains all characters of string y

Find minimum window width in string x that contains all characters of another string y. For example:
String x = "coobdafceeaxab"
String y = "abc"
The answer should be 5, because the shortest substring in x that contains all three letters of y is "bdafc".
I can think of a naive solution with complexity O(n^2 * log(m)), where n = len(x) and m = len(y). Can anyone suggest a better solution? Thanks.
Update: now think of it, if I change my set to tr1::unordered_map, then I can cut the complexity down to O(n^2), because insertion and deletion should both be O(1).
time: O(n) (One pass)
space: O(k)
This is how I would do it:
Create a hash table for all the characters from string Y. (I assume all characters are different in Y).
First pass:
Start from first character of string X.
update hash table, for exa: for key 'a' enter location (say 1).
Keep on doing it until you get all characters from Y (until all key in hash table has value).
If you get some character again, update its newer value and erase older one.
Once you have first pass, take smallest value from hash table and biggest value.
Thats the minimum window observed so far.
Now, go to next character in string X, update hash table and see if you get smaller window.
Edit:
Lets take an example here:
String x = "coobdafceeaxab"
String y = "abc"
First initialize a hash table from characters of Y.
h[a] = -1
h[b] = -1
h[c] = -1
Now, Start from first character of X.
First character is c, h[c] = 0
Second character (o) is not part of hash, skip it.
..
Fourth character (b), h[b] = 3
..
Sixth character(a), enter hash table h[a] = 5.
Now, all keys from hash table has some value.
Smallest value is 0 (of c) and highest value is 5 (of a), minimum window so far is 6 (0 to 5).
First pass is done.
Take next character. f is not part of hash table, skip it.
Next character (c), update hash table h[c] = 7.
Find new window, smallest value is 3 (of b) and highest value is 7 (of c).
New window is 3 to 7 => 5.
Keep on doing it till last character of string X.
I hope its clear now.
Edit
There are some concerns about finding max and min value from hash.
We can maintain sorted Link-list and map it with hash table.
Whenever any element from Link list changes, it should be re-mapped to hash table.
Both these operation are O(1)
Total space would be m+m
Edit
Here is small visualisation of above problem:
For "coobdafceeaxab" and "abc"
step-0:
Initial doubly linked-list = NULL
Initial hash-table = NULL
step-1:
Head<->[c,0]<->tail
h[c] = [0, 'pointer to c node in LL']
step-2:
Head<->[c,0]<->[b,3]<->tail
h[c] = [0, 'pointer to c node in LL'], h[b] = [3, 'pointer to b node in LL'],
Step-3:
Head<->[c,0]<->[b,3]<->[a,5]<->tail
h[c] = [0, 'pointer to c node in LL'], h[b] = [3, 'pointer to b node in LL'], h[a] = [5, 'pointer to a node in LL']
Minimum Window => difference from tail and head => (5-0)+1 => Length: 6
Step-4:
Update entry of C to index 7 here. (Remove 'c' node from linked-list and append at the tail)
Head<->[b,3]<->[a,5]<->[c,7]<->tail
h[c] = [7, 'new pointer to c node in LL'], h[b] = [3, 'pointer to b node in LL'], h[a] = [5, 'pointer to a node in LL'],
Minimum Window => difference from tail and head => (7-3)+1 => Length: 5
And so on..
Note that above Linked-list update and hash table update are both O(1).
Please correct me if I am wrong..
Summary:
TIme complexity: O(n) with one pass
Space Complexity: O(k) where k is length of string Y
I found this very nice O(N) time complexity version here http://leetcode.com/2010/11/finding-minimum-window-in-s-which.html, and shortened it slightly (removed continue in a first while , which allowed to simplify condition for the second while loop). Note, that this solution allows for duplicates in the second string, while many of the above answers do not.
private static String minWindow(String s, String t) {
int[] needToFind = new int[256];
int[] hasFound = new int[256];
for(int i = 0; i < t.length(); ++i) {
needToFind[t.charAt(i)]++;
}
int count = 0;
int minWindowSize = Integer.MAX_VALUE;
int start = 0, end = -1;
String window = "";
while (++end < s.length()) {
char c = s.charAt(end);
if(++hasFound[c] <= needToFind[c]) {
count++;
}
if(count < t.length()) continue;
while (hasFound[s.charAt(start)] > needToFind[s.charAt(start)]) {
hasFound[s.charAt(start++)]--;
}
if(end - start + 1 < minWindowSize) {
minWindowSize = end - start + 1;
window = s.substring(start, end + 1);
}
}
return window;
}
Here's my solution in C++:
int min_width(const string& x, const set<char>& y) {
vector<int> at;
for (int i = 0; i < x.length(); i++)
if (y.count(x[i]) > 0)
at.push_back(i);
int ret = x.size();
int start = 0;
map<char, int> count;
for (int end = 0; end < at.size(); end++) {
count[x[at[end]]]++;
while (count[x[at[start]]] > 1)
count[x[at[start++]]]--;
if (count.size() == y.size() && ret > at[end] - at[start] + 1)
ret = at[end] - at[start] + 1;
}
return ret;
}
Edit: Here's an implementation of Jack's idea. It's the same time complexity as mine, but without the inner loop that confuses you.
int min_width(const string& x, const set<char>& y) {
int ret = x.size();
map<char, int> index;
set<int> index_set;
for (int j = 0; j < x.size(); j++) {
if (y.count(x[j]) > 0) {
if (index.count(x[j]) > 0)
index_set.erase(index[x[j]]);
index_set.insert(j);
index[x[j]] = j;
if (index.size() == y.size()) {
int i = *index_set.begin();
if (ret > j-i+1)
ret = j-i+1;
}
}
}
return ret;
}
In Java it can be implemented nicely with LinkedHashMap:
static int minWidth(String x, HashSet<Character> y) {
int ret = x.length();
Map<Character, Integer> index = new LinkedHashMap<Character, Integer>();
for (int j = 0; j < x.length(); j++) {
char ch = x.charAt(j);
if (y.contains(ch)) {
index.remove(ch);
index.put(ch, j);
if (index.size() == y.size()) {
int i = index.values().iterator().next();
if (ret > j - i + 1)
ret = j - i + 1;
}
}
}
return ret;
}
All operations inside the loop take constant time (assuming hashed elements disperse properly).
There is an O(n solution to this problem). It very well described in this article.
http://www.leetcode.com/2010/11/finding-minimum-window-in-s-which.html
Hope it helps.
This is my solution in C++, just for reference.
Update: originally I used std::set, now I change it to tr1::unordered_map to cut complexity down to n^2, otherwise these two implementations look pretty similar, to prevent this post from getting too long, I only list the improved solution.
#include <iostream>
#include <tr1/unordered_map>
#include <string>
using namespace std;
using namespace std::tr1;
typedef tr1::unordered_map<char, int> hash_t;
// Returns min substring width in which sentence contains all chars in word
// Returns sentence's length + 1 if not found
size_t get_min_width(const string &sent, const string &word) {
size_t min_size = sent.size() + 1;
hash_t char_set; // char set that word contains
for (size_t i = 0; i < word.size(); i++) {
char_set.insert(hash_t::value_type(word[i], 1));
}
for (size_t i = 0; i < sent.size() - word.size(); i++) {
hash_t s = char_set;
for (size_t j = i; j < min(j + min_size, sent.size()); j++) {
s.erase(sent[j]);
if (s.empty()) {
size_t size = j - i + 1;
if (size < min_size) min_size = size;
break;
}
}
}
return min_size;
}
int main() {
const string x = "coobdafceeaxab";
const string y = "abc";
cout << get_min_width(x, y) << "\n";
}
An implementation of Jack's idea.
public int smallestWindow(String str1, String str2){
if(str1==null || str2==null){
throw new IllegalArgumentException();
}
Map<String, Node> map=new HashMap<String, Node>();
Node head=null, current=null;
for(int i=0;i<str1.length();i++){
char c=str1.charAt(i);
if(head==null){
head=new Node(c);
current=head;
map.put(String.valueOf(c), head);
}
else{
current.next=new Node(c);
current.next.pre=current;
current=current.next;
map.put(String.valueOf(c), current);
}
}
Node end=current;
int min=Integer.MAX_VALUE;
int count=0;
for(int i=0;i<str2.length();i++){
char c = str2.charAt(i);
Node n=map.get(String.valueOf(c));
if(n!=null){
if(n.index==Integer.MAX_VALUE){
count++;
}
n.index=i;
if(n==head){
Node temp=head;
head=head.next;
if(head==null){//one node
return 1;
}
head.pre=null;
temp.pre=end;
end.next=temp;
temp.next=null;
end=temp;
}
else if(end!=n){
n.pre.next=n.next;
n.next.pre=n.pre;
n.pre=end;
n.next=null;
end.next=n;
end=n;
}
if(count==str1.length()){
min=Math.min(end.index-head.index+1, min);
}
}
}
System.out.println(map);
return min;
}
Simple java solution using the sliding window. Extending NitishMD's idea above:
public class StringSearchDemo {
public String getSmallestSubsetOfStringContaingSearchString(String toMatch,
String inputString) {
if (inputString.isEmpty() || toMatch.isEmpty()) {
return null;
}
// List<String> results = new ArrayList<String>(); // optional you can comment this out
String smallestMatch = "";
// String largestMatch = "";
int startPointer = 0, endPointer = 1;
HashMap<Character, Integer> toMatchMap = new HashMap<Character, Integer>();
for (char c : toMatch.toCharArray()) {
if (toMatchMap.containsKey(c)) {
toMatchMap.put(c, (toMatchMap.get(c) + 1));
} else {
toMatchMap.put(c, 1);
}
}
int totalCount = getCountofMatchingString(toMatchMap, toMatch);
for (int i = 0; i < inputString.length();) {
if (!toMatchMap.containsKey(inputString.charAt(i))) {
endPointer++;
i++;
continue;
}
String currentSubString = inputString.substring(startPointer,
endPointer);
if (getCountofMatchingString(toMatchMap, currentSubString) >= totalCount) {
// results.add(currentSubString); // optional you can comment this out
if (smallestMatch.length() > currentSubString.length()) {
smallestMatch = currentSubString;
} else if (smallestMatch.isEmpty()) {
smallestMatch = currentSubString;
}
// if (largestMatch.length() < currentSubString.length()) {
// largestMatch = currentSubString;
// }
startPointer++;
} else {
endPointer++;
i++;
}
}
// System.out.println("all possible combinations = " + results); // optional, you can comment this out
// System.out.println("smallest result = " + smallestMatch);
// System.out.println("largest result = " + largestMatch);
return smallestMatch;
}
public int getCountofMatchingString(HashMap<Character, Integer> toMatchMap,
String toMatch) {
int match = 0;
HashMap<Character, Integer> localMap = new HashMap<Character, Integer>();
for (char c : toMatch.toCharArray()) {
if (toMatchMap.containsKey(c)) {
if (localMap.containsKey(c)) {
if (localMap.get(c) < toMatchMap.get(c)) {
localMap.put(c, (localMap.get(c) + 1));
match++;
}
} else {
localMap.put(c, 1);
match++;
}
}
}
return match;
}
public static void main(String[] args) {
String inputString = "zxaddbddxyy由ccbbwwaay漢字由来";
String matchCriteria = "a由";
System.out.println("input=" + matchCriteria);
System.out.println("matchCriteria=" + inputString);
String result = (new StringSearchDemo())
.getSmallestSubsetOfStringContaingSearchString(matchCriteria, inputString);
System.out.println("smallest possbile match = " + result);
}
}

Given an array of numbers, find out if 3 of them add up to 0

Given an array of numbers, find out if 3 of them add up to 0.
Do it in N^2, how would one do this?
O(n^2) solution without hash tables (because using hash tables is cheating :P). Here's the pseudocode:
Sort the array // O(nlogn)
for each i from 1 to len(array) - 1
iter = i + 1
rev_iter = len(array) - 1
while iter < rev_iter
tmp = array[iter] + array[rev_iter] + array[i]
if tmp > 0
rev_iter--
else if tmp < 0
iter++
else
return true
return false
Basically using a sorted array, for each number (target) in an array, you use two pointers, one starting from the front and one starting from the back of the array, check if the sum of the elements pointed to by the pointers is >, < or == to the target, and advance the pointers accordingly or return true if the target is found.
Not for credit or anything, but here is my python version of Charles Ma's solution. Very cool.
def find_sum_to_zero(arr):
arr = sorted(arr)
for i, target in enumerate(arr):
lower, upper = 0, len(arr)-1
while lower < i < upper:
tmp = target + arr[lower] + arr[upper]
if tmp > 0:
upper -= 1
elif tmp < 0:
lower += 1
else:
yield arr[lower], target, arr[upper]
lower += 1
upper -= 1
if __name__ == '__main__':
# Get a list of random integers with no duplicates
from random import randint
arr = list(set(randint(-200, 200) for _ in range(50)))
for s in find_sum_to_zero(arr):
print s
Much later:
def find_sum_to_zero(arr):
limits = 0, len(arr) - 1
arr = sorted(arr)
for i, target in enumerate(arr):
lower, upper = limits
while lower < i < upper:
values = (arr[lower], target, arr[upper])
tmp = sum(values)
if not tmp:
yield values
lower += tmp <= 0
upper -= tmp >= 0
put the negative of each number into a hash table or some other constant time lookup data structure. (n)
loop through the array getting each set of two numbers (n^2), and see if their sum is in the hash table.
First sort the array, then for each negative number (A) in the array, find two elements in the array adding up to -A. Finding 2 elements in a sorted array that add up to the given number takes O(n) time, so the entire time complexity is O(n^2).
C++ implementation based on the pseudocode provided by Charles Ma, for anyone interested.
#include <iostream>
using namespace std;
void merge(int originalArray[], int low, int high, int sizeOfOriginalArray){
// Step 4: Merge sorted halves into an auxiliary array
int aux[sizeOfOriginalArray];
int auxArrayIndex, left, right, mid;
auxArrayIndex = low;
mid = (low + high)/2;
right = mid + 1;
left = low;
// choose the smaller of the two values "pointed to" by left, right
// copy that value into auxArray[auxArrayIndex]
// increment either left or right as appropriate
// increment auxArrayIndex
while ((left <= mid) && (right <= high)) {
if (originalArray[left] <= originalArray[right]) {
aux[auxArrayIndex] = originalArray[left];
left++;
auxArrayIndex++;
}else{
aux[auxArrayIndex] = originalArray[right];
right++;
auxArrayIndex++;
}
}
// here when one of the two sorted halves has "run out" of values, but
// there are still some in the other half; copy all the remaining values
// to auxArray
// Note: only 1 of the next 2 loops will actually execute
while (left <= mid) {
aux[auxArrayIndex] = originalArray[left];
left++;
auxArrayIndex++;
}
while (right <= high) {
aux[auxArrayIndex] = originalArray[right];
right++;
auxArrayIndex++;
}
// all values are in auxArray; copy them back into originalArray
int index = low;
while (index <= high) {
originalArray[index] = aux[index];
index++;
}
}
void mergeSortArray(int originalArray[], int low, int high){
int sizeOfOriginalArray = high + 1;
// base case
if (low >= high) {
return;
}
// Step 1: Find the middle of the array (conceptually, divide it in half)
int mid = (low + high)/2;
// Steps 2 and 3: Recursively sort the 2 halves of origianlArray and then merge those
mergeSortArray(originalArray, low, mid);
mergeSortArray(originalArray, mid + 1, high);
merge(originalArray, low, high, sizeOfOriginalArray);
}
//O(n^2) solution without hash tables
//Basically using a sorted array, for each number in an array, you use two pointers, one starting from the number and one starting from the end of the array, check if the sum of the three elements pointed to by the pointers (and the current number) is >, < or == to the targetSum, and advance the pointers accordingly or return true if the targetSum is found.
bool is3SumPossible(int originalArray[], int targetSum, int sizeOfOriginalArray){
int high = sizeOfOriginalArray - 1;
mergeSortArray(originalArray, 0, high);
int temp;
for (int k = 0; k < sizeOfOriginalArray; k++) {
for (int i = k, j = sizeOfOriginalArray-1; i <= j; ) {
temp = originalArray[k] + originalArray[i] + originalArray[j];
if (temp == targetSum) {
return true;
}else if (temp < targetSum){
i++;
}else if (temp > targetSum){
j--;
}
}
}
return false;
}
int main()
{
int arr[] = {2, -5, 10, 9, 8, 7, 3};
int size = sizeof(arr)/sizeof(int);
int targetSum = 5;
//3Sum possible?
bool ans = is3SumPossible(arr, targetSum, size); //size of the array passed as a function parameter because the array itself is passed as a pointer. Hence, it is cummbersome to calculate the size of the array inside is3SumPossible()
if (ans) {
cout<<"Possible";
}else{
cout<<"Not possible";
}
return 0;
}
This is my approach using Swift 3 in N^2 log N...
let integers = [-50,-40, 10, 30, 40, 50, -20, -10, 0, 5]
First step, sort array
let sortedArray = integers.sorted()
second, implement a binary search method that returns an index like so...
func find(value: Int, in array: [Int]) -> Int {
var leftIndex = 0
var rightIndex = array.count - 1
while leftIndex <= rightIndex {
let middleIndex = (leftIndex + rightIndex) / 2
let middleValue = array[middleIndex]
if middleValue == value {
return middleIndex
}
if value < middleValue {
rightIndex = middleIndex - 1
}
if value > middleValue {
leftIndex = middleIndex + 1
}
}
return 0
}
Finally, implement a method that keeps track of each time a set of "triplets" sum 0...
func getTimesTripleSumEqualZero(in integers: [Int]) -> Int {
let n = integers.count
var count = 0
//loop the array twice N^2
for i in 0..<n {
for j in (i + 1)..<n {
//Sum the first pair and assign it as a negative value
let twoSum = -(integers[i] + integers[j])
// perform a binary search log N
// it will return the index of the give number
let index = find(value: twoSum, in: integers)
//to avoid duplications we need to do this check by checking the items at correspondingly indexes
if (integers[i] < integers[j] && integers[j] < integers[index]) {
print("\([integers[i], integers[j], integers[index]])")
count += 1
}
}
}
return count
}
print("count:", findTripleSumEqualZeroBinary(in: sortedArray))
prints--- count: 7
void findTriplets(int arr[], int n)
{
bool found = false;
for (int i=0; i<n-1; i++)
{
unordered_set<int> s;
for (int j=i+1; j<n; j++)
{
int x = -(arr[i] + arr[j]);
if (s.find(x) != s.end())
{
printf("%d %d %d\n", x, arr[i], arr[j]);
found = true;
}
else
s.insert(arr[j]);
}
}
if (found == false)
cout << " No Triplet Found" << endl;
}

Resources