Can anybody take a look at my CPP code?
It's from this problem: https://leetcode.com/problems/capacity-to-ship-packages-within-d-days/
I feel very frustrated cuz though my python code works, my cpp code doesn't work as always. :pensive: Same idea, different results. It drives me crazy.
The correct output should be 15.
My Python code returns the right output 15 while my CPP code returns the wrong output 10.
My python code:
def cnt_days(weights, k):
total, cnt = 0, 1
for w in weights:
if total + w > k:
total = 0
cnt += 1
total += w
print(total, cnt)
return cnt
def shipWithinDays(weights, D):
left = max(weights)
right = max(weights) * len(weights) // D + 1
while left < right:
mid = left + (right - left) // 2
if cnt_days(weights, mid) > D:
left = mid + 1
else:
right = mid
return left
if __name__ == "__main__":
print(shipWithinDays([1,2,3,4,5,6,7,8,9,10], 5))
My cpp code:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int cnt_days(vector<int>& weights, int K)
{
int total = 0, cnt = 1;
for (int w: weights)
{
if (total + w > K)
{
total = 0;
cnt++;
}
else total += w;
}
cout << total <<" "<< cnt << endl;
return cnt;
}
int shipWithinDays(vector<int>& weights, int D)
{
int maximum = *max_element(weights.begin(), weights.end());
int left = maximum;
int right = maximum * weights.size() / D + 1;
while (left < right)
{
int mid = left + (right - left)/2;
if (cnt_days(weights, mid) > D)
left = mid + 1;
else
right = mid;
}
return left;
}
int main()
{
vector<int> weights = {1,2,3,4,5,6,7,8,9,10};
int D = 5;
cout << shipWithinDays(weights, D) << endl;
return 0;
}
Maybe, you could binary search much simple for your c++ solution:
#include <vector>
class Solution {
public:
int shipWithinDays(std::vector<int>& weights, int d) {
int lo = 0;
int hi = INT_MAX;
for (int weight : weights) {
lo = max(lo, weight);
}
while (lo < hi) {
int mid = lo + (hi - lo) / 2;
int required = 1;
int cur = 0;
for (int index = 0; index < weights.size() && required <= d; cur += weights[index++])
if (cur + weights[index] > mid) {
cur = 0;
required++;
}
if (required > d) {
lo = mid + 1;
} else {
hi = mid;
}
}
return lo;
}
};
Or with basic bitwise operations:
class Solution {
public:
int shipWithinDays(vector<int> &weights, int d) {
int lo = 0;
int hi = INT_MAX;
for (int weight : weights)
lo = max(lo, weight);
while (lo < hi) {
int mid = lo + ((hi - lo) >> 1);
int required = 1;
int cur = 0;
for (int index = 0; index < weights.size() && required <= d; cur += weights[index++])
if (cur + weights[index] > mid)
cur = 0, required++;
if (required > d)
lo = -~mid;
else
hi = mid;
}
return lo;
}
};
Similarly for python:
from typing import List
class Solution:
def shipWithinDays(self, weights: List[int], d: int) -> int:
lo, hi = max(weights), sum(weights)
while lo < hi:
mid = lo + ((hi - lo) >> 1) # or mid = (lo + hi) // 2 || mid = lo + (hi - lo) // 2
cur, required = 0, 1
for weight in weights:
if cur + weight > mid:
required += 1
cur = 0
cur += weight
if required > d:
lo = -~mid # simply lo = mid + 1
else:
hi = mid
return lo
References
For additional details, you can see the Discussion Board. There are plenty of accepted solutions, explanations, efficient algorithms with a variety of languages, and time/space complexity analysis in there.
remove the else
else total += w;
should be
total += w;
Related
Given an array A of n integers and given queries in the form of range [l , r] and a value x, find the minimum of A[i] XOR x where l <= i <= r and x will be different for different queries.
I tried solving this problem using segment trees but I am not sure what type of information I should store in them as x will be different for different queries.
0 < number of queries <= 1e4
0 < n <= 1e4
To solve this I used a std::vector as basis (not an array, or std::array), just for flexibility.
#include <algorithm>
#include <stdexcept>
#include <vector>
int get_xored_max(const std::vector<int>& values, const size_t l, const size_t r, const int xor_value)
{
// check bounds of l and r
if ((l >= values.size()) || (r >= values.size()))
{
throw std::invalid_argument("index out of bounds");
}
// todo check l < r
// create left & right iterators to create a smaller vector
// only containing the subset we're interested in.
auto left = values.begin() + l;
auto right = values.begin() + r + 1;
std::vector<int> range{ left, right };
// xor all the values in the subset
for (auto& v : range)
{
v ^= xor_value;
}
// use the standard library function for finding the iterator to the maximum
// then use the * to dereference the iterator and get the value
auto max_value = *std::max_element(range.begin(), range.end());
return max_value;
}
int main()
{
std::vector<int> values{ 1,3,5,4,2,4,7,9 };
auto max_value = get_xored_max(values, 0u, 7u, 3);
return 0;
}
Approach - Trie + Offline Processing
Time Complexity - O(N32)
Space Complexity - O(N32)
Edit:
This Approach will fail. I guess, we have to use square root decomposition instead of two pointers approach.
I have solved this problem using Trie for finding minimum xor in a range of [l,r]. I solved queries by offline processing by sorting them.
Input format:
the first line has n (no. of elements) and q (no. of queries). the second line has all n elements of the array. each subsequent line has a query and each query has 3 inputs l, r and x.
Example -
Input -
3 3
2 1 2
1 2 3
1 3 2
2 3 5
First, convert all 3 queries into queries sorted by l and r.
converted queries -
1 2 3
1 3 2
2 3 5
Key here is processing over sorted queries using two pointers approach.
#include <bits/stdc++.h>
using namespace std;
const int N = (int)2e4 + 77;
int n, q, l, r, x;
int a[N], ans[N];
vector<pair<pair<int, int>, pair<int, int>>> queries;
// Trie Implementation starts
struct node
{
int nxt[2], cnt;
void newnode()
{
memset(nxt, 0, sizeof(nxt));
cnt = 0;
}
} trie[N * 32];
int tot = 1;
void update(int x, int v)
{
int p = 1;
for (int i = 31; i >= 0; i--)
{
int id = x >> i & 1;
if (!trie[p].nxt[id])
{
trie[++tot].newnode();
trie[p].nxt[id] = tot;
}
p = trie[p].nxt[id];
trie[p].cnt += v;
}
}
int minXor(int x)
{
int res = 0, p = 1;
for (int i = 31; i >= 0; i--)
{
int id = x >> i & 1;
if (trie[p].nxt[id] and trie[trie[p].nxt[id]].cnt)
p = trie[p].nxt[id];
else
{
p = trie[p].nxt[id ^ 1];
res |= 1 << i;
}
}
return res;
}
// Trie Implementation ends
int main()
{
cin >> n >> q;
for (int i = 1; i <= n; i += 1)
{
cin >> a[i];
}
for (int i = 1; i <= q; i += 1)
{
cin >> l >> r >> x;
queries.push_back({{l, r}, {x, i}});
}
sort(queries.begin(), queries.end());
int left = 1, right = 1;
for (int i = 0; i < q; i += 1)
{
int l = queries[i].first.first;
int r = queries[i].first.second;
int x = queries[i].second.first;
int index = queries[i].second.second;
while (left < l)
{
update(a[left], -1);
left += 1;
}
while (right <= r)
{
update(a[right], 1);
right += 1;
}
ans[index] = minXor(x);
}
for (int i = 1; i <= q; i += 1)
{
cout << ans[i] << " \n";
}
return 0;
}
Edit: with O(number of bits) code
Use a binary tree to store the values of A, look here : Minimum XOR for queries
What you need to change is adding to each node the range of indexes for A corresponding to the values in the leafs.
# minimal xor in a range
nbits=16 # Number of bits for numbers
asize=5000 # Array size
ntest=50 # Number of random test
from random import randrange
# Insert element a iindex iin the tree (increasing i only)
def tinsert(a,i,T):
for b in range(nbits-1,-1,-1):
v=((a>>b)&1)
T[v+2].append(i)
if T[v]==[]:T[v]=[[],[],[],[]]
T=T[v]
# Buildtree : builds a tree based on array V
def build(V):
T=[[],[],[],[]] # Init tree
for i,a in enumerate(V): tinsert(a,i,T)
return(T)
# Binary search : is T intersec [a,b] non empty ?
def binfind(T,a,b):
s,e,om=0,len(T)-1,-1
while True:
m=(s+e)>>1
v=T[m]
if v<a:
s=m
if m==om: return(a<=T[e]<=b)
elif v>b:
e=m
if m==om: return(a<=T[s]<=b)
else: return(True) # a<=T(m)<=b
om=m
# Look for the min xor in a give range index
def minx(x,s,e,T):
if s<0 or s>=(len(T[2])+len(T[3])) or e<s: return
r=0
for b in range(nbits-1,-1,-1):
v=((x>>b)&1)
if T[v+2]==[] or not binfind(T[v+2],s,e): # not nr with b set to v ?
v=1-v
T=T[v]
r=(r<<1)|v
return(r)
# Tests the code on random arrays
max=(1<<nbits)-1
for i in range(ntest):
A=[randrange(0,max) for i in range(asize)]
T=build(A)
x,s=randrange(0,max),randrange(0,asize-1)
e=randrange(s,asize)
if min(v^x for v in A[s:e+1])!=x^minx(x,s,e,T):
print('error')
I was able to solve this using segment tree and tries as suggested by #David Eisenstat
Below is an implementation in c++.
I constructed a trie for each segment in the segment tree. And finding the minimum xor is just traversing and matching the corresponding trie using each bit of the query value (here)
#include <bits/stdc++.h>
#define rep(i, a, b) for (int i = a; i < b; i++)
using namespace std;
const int bits = 7;
struct trie {
trie *children[2];
bool end;
};
trie *getNode(void)
{
trie *node = new trie();
node->end = false;
node->children[0] = NULL;
node->children[1] = NULL;
return node;
}
trie *merge(trie *l, trie *r)
{
trie *node = getNode();
// Binary 0:
if (l->children[0] && r->children[0])
node->children[0] = merge(l->children[0], r->children[0]);
else if (!r->children[0])
node->children[0] = l->children[0];
else if (!l->children[0])
node->children[0] = r->children[0];
// Binary 1:
if (l->children[1] && r->children[1])
node->children[1] = merge(l->children[1], r->children[1]);
else if (!r->children[1])
node->children[1] = l->children[1];
else if (!l->children[1])
node->children[1] = r->children[1];
return node;
}
void insert(trie *root, int num)
{
int mask = 1 << bits;
int bin;
rep(i, 0, bits + 1)
{
bin = ((num & mask) >> (bits - i));
if (!root->children[bin]) root->children[bin] = getNode();
root = root->children[bin];
mask = mask >> 1;
}
root->end = true;
}
struct _segTree {
int n, height, size;
vector<trie *> tree;
_segTree(int _n)
{
n = _n;
height = (int)ceil(log2(n));
size = (int)(2 * pow(2, height) - 1);
tree.resize(size);
}
trie *construct(vector<int> A, int start, int end, int idx)
{
if (start == end) {
tree[idx] = getNode();
insert(tree[idx], A[start]);
return tree[idx];
}
int mid = start + (end - start) / 2;
tree[idx] = merge(construct(A, start, mid, 2 * idx + 1),
construct(A, mid + 1, end, 2 * idx + 2));
return tree[idx];
}
int findMin(int num, trie *root)
{
int mask = 1 << bits;
int bin;
int rnum = 0;
int res = 0;
rep(i, 0, bits + 1)
{
bin = ((num & mask) >> (bits - i));
if (!root->children[bin]) {
bin = 1 - bin;
if (!root->children[bin]) return res ^ num;
}
rnum |= (bin << (bits - i));
root = root->children[bin];
if (root->end) res = rnum;
mask = mask >> 1;
}
return res ^ num;
}
int Query(int X, int start, int end, int qstart, int qend, int idx)
{
if (qstart <= start && qend >= end) return findMin(X, tree[idx]);
if (qstart > end || qend < start) return INT_MAX;
int mid = start + (end - start) / 2;
return min(Query(X, start, mid, qstart, qend, 2 * idx + 1),
Query(X, mid + 1, end, qstart, qend, 2 * idx + 2));
}
};
int main()
{
int n, q;
vector<int> A;
vector<int> L;
vector<int> R;
vector<int> X;
cin >> n;
A.resize(n, 0);
rep(i, 0, n) cin >> A[i];
cin >> q;
L.resize(q);
R.resize(q);
X.resize(q);
rep(i, 0, q) cin >> L[i] >> R[i] >> X[i];
//---------------------code--------------------//
_segTree segTree(n);
segTree.construct(A, 0, n - 1, 0);
rep(i, 0, q)
{
cout << segTree.Query(X[i], 0, n - 1, L[i], R[i], 0) << " ";
}
return 0;
}
Time complexity : O((2n - 1)*k + qklogn)
Space complexity : O((2n - 1)*2k)
k -> number of bits
I try to implement A* algorithm with both manhattan distance and manhattan distance + linear conflict heuristic.
but my manhattan distance works much better and I can't understand why!
manhattan distance + linear conflict in my algorithm expands much more node and i found that it's answer it not even optimal.
#include <iostream>
#include <time.h>
#include <fstream>
#include <set>
#include <vector>
#include <queue>
#include <map>
#include "node.h"
using namespace std;
const int n = 4;
const int hash_base = 23;
const long long hash_mod = 9827870924701019;
set<long long> explored;
set<pair<int , node*> > frontier;
map<string,int> database[3];
void check(int* state){
for(int j = 0 ; j < n ; j++){
for(int i = 0 ; i < n ; i++)
cerr << state[j * n + i] << " ";
cerr << endl;
}
cerr << endl;
}
bool goal_test(int* state){
if(state[n * n - 1] != 0) return 0;
for(int i = 0 ; i < (n * n - 1) ; i++){
if(state[i] != i + 1)
return 0;
}
return 1;
}
vector<node> solution(node* v){
vector<node> ans;
while((v->parent)->hash != v->hash){
ans.push_back(*v);
v = v->parent;
}
return ans;
}
//first heuristic
int manhattanDistance(int* state){
int md = 0;
for(int i = 0 ; i < (n * n) ; i++){
if(state[i] == 0) continue;
//what is the goal row and column of this tile
int gr = (state[i] - 1) / n , gc = (state[i] - 1) % n;
//what is the row and column of this tile
int r = i / n , c = i % n;
md += (max(gr - r , r - gr) + max(gc - c , c - gc));
}
return md;
}
//second heuristic
int linearConflict(int* state){
int lc = 0;
for(int i = 0 ; i < n ; i++){
for(int j = 0 ; j < n ; j++){
//jth tile in ith row = (i * n + j)th in state
int la = i * n + j;
if(state[la] == 0 || (state[la] / n) != i)
continue;
for(int k = j + 1 ; k < n ; k++){
//kth tile in ith row = (i * n + k)th in state
int lb = i * n + k;
if(state[lb] == 0 || (state[lb] / n) != i)
continue;
if(state[la] > state[lb])
lc++;
}
}
}
for(int i = 0 ; i < n ; i++){
for(int j = 0 ; j < n ; j++){
//j the tile of i th column
int la = j * 4 + i;
if(state[la] == 0 || (state[la] % n) != i)
continue;
for(int k = j + 1 ; k < n ; k++){
int lb = k * 4 + i;
if(state[lb] == 0 || (state[lb] % n) != i)
continue;
if(state[la] > state[lb])
lc++;
}
}
}
return lc * 2;
}
long long make_hash(int* v){
long long power = 1LL;
long long hash = 0 * 1LL;
for(int i = 0 ; i < (n * n) ; i++){
hash += (power * v[i] * 1LL) % hash_mod;
hash %= hash_mod;
power = (hash_base * power * 1LL) % hash_mod;
}
return hash;
}
vector<node> successor(node* parent){
vector<node> child;
int parent_empty = parent->empty_cell;
//the row and column of empty cell
int r = parent_empty / n , c = parent_empty % n;
//empty cell go down
if(r + 1 < n){
struct node down;
for(int i = 0 ; i < (n*n) ; i++)
down.state[i] = parent->state[i];
down.state[parent_empty] = parent->state[parent_empty + n];
down.state[parent_empty + n] = 0;
down.hash = make_hash(down.state);
down.empty_cell = parent_empty + n;
down.cost = parent->cost + 1;
down.parent = parent;
//first heuristic -> manhattan Distance
// down.heuristic = manhattanDistance(down.state);
//second heuristic -> manhattan distance + linear conflict
down.heuristic = linearConflict(down.state) + manhattanDistance(down.state);
//third heuristic -> disjoint pattern database
// down.heuristic = DisjointPatternDB(down.state);
child.push_back(down);
}
//empty cell go up
if(r - 1 >= 0){
struct node up;
for(int i = 0 ; i < n * n ; i++)
up.state[i] = parent->state[i];
up.state[parent_empty] = parent->state[parent_empty - n];
up.state[parent_empty - n] = 0;
up.empty_cell = parent_empty - n;
up.hash = make_hash(up.state);
up.cost = parent->cost + 1;
up.parent = parent;
//first heuristic -> manhattan Distance
// up.heuristic = manhattanDistance(up.state);
//second heuristic -> manhattan distance + linear conflict
up.heuristic = linearConflict(up.state) + manhattanDistance(up.state);
//third heuristic -> disjoint pattern database
// up.heuristic = DisjointPatternDB(up.state);
child.push_back(up);
}
//empty cell going right
if(c + 1 < n){
struct node right;
for(int i = 0 ; i < (n * n) ; i++)
right.state[i] = parent->state[i];
right.state[parent_empty] = parent->state[parent_empty + 1];
right.state[parent_empty + 1] = 0;
right.empty_cell = parent_empty + 1;
right.hash = make_hash(right.state);
right.cost = parent->cost + 1;
right.parent = parent;
//first heuristic -> manhattan Distance
// right.heuristic = manhattanDistance(right.state);
//second heuristic -> manhattan distance + linear conflict
right.heuristic = linearConflict(right.state) + manhattanDistance(right.state);
//third heuristic -> disjoint pattern database
// right.heuristic = DisjointPatternDB(right.state);
child.push_back(right);
}
//empty cell going left
if(c - 1 >= 0){
struct node left;
for (int i = 0; i < (n * n) ; i++)
left.state[i] = parent->state[i];
left.state[parent_empty] = parent->state[parent_empty - 1];
left.state[parent_empty - 1] = 0;
left.empty_cell = parent_empty - 1;
left.hash = make_hash(left.state);
left.cost = parent->cost + 1;
left.parent = parent;
//first heuristic -> manhattan Distance
// left.heuristic = manhattanDistance(left.state);
//second heuristic -> manhattan distance + linear conflict
left.heuristic = linearConflict(left.state) + manhattanDistance(left.state);
//third heuristic -> disjoint pattern database
// left.heuristic = DisjointPatternDB(left.state);
child.push_back(left);
}
return child;
}
node* nodeCopy(node child){
node* tmp = new node;
for(int i = 0 ; i < n * n; i++)
tmp->state[i] = child.state[i];
tmp->hash = child.hash;
tmp->empty_cell = child.empty_cell;
tmp->cost = child.cost;
tmp->parent = child.parent;
tmp->heuristic = child.heuristic;
return tmp;
}
vector<node> Astar(node* initNode){
if(goal_test(initNode->state)) return solution(initNode);
frontier.insert(make_pair(initNode->cost + initNode-> heuristic ,initNode));
explored.insert(initNode->hash);
while(!frontier.empty()){
node* v = (*frontier.begin()).second;
if(goal_test(v->state)) return solution(v);
frontier.erase(frontier.begin());
vector<node> childs = successor(v);
for(node child: childs){
if(explored.find(child.hash) == explored.end()){
node* tmp = nodeCopy(child);
frontier.insert(make_pair((child.cost + child.heuristic) , tmp));
explored.insert(child.hash);
}
}
}
return solution(initNode);
}
int main(){
clock_t tStart = clock();
printf("Time taken: %.2fs\n", (double)(clock() - tStart)/CLOCKS_PER_SEC);
struct node init;// {{1 , 2 , 3 , 4 , 5, 6, 7, 8, 0} , 1 , 9 , 0 , &init , 0};
for(int i = 0 ; i < (n * n) ; i++){
cin >> init.state[i];
if(init.state[i] == 0)
init.empty_cell = i;
}
init.hash = make_hash(init.state);
init.cost = 0;
init.parent = &init;
init.heuristic = manhattanDistance(init.state) ;//+ linearConflict(init.state);
vector <node> ans = Astar(&init);
//cout << 1 << " ";
for(int j = 0 ; j < n * n ; j++){
if(j == n * n - 1) cout << init.state[j];
else cout << init.state[j] << ",";
}
cout << endl;
for(int i = (ans.size() - 1) ; i >= 0 ; i--){
//cout << (ans.size() - i + 1) << " ";
cerr << linearConflict(ans[i].state) << endl;
for(int j = 0 ; j < n * n ; j++){
if(j == n * n - 1) cout << ans[i].state[j];
else cout << ans[i].state[j] << ",";
}
cout << endl;
}
cout << "path size : " << ans.size() << endl;
cout << "number of node expanded : " << explored.size() << endl;
printf("Time taken: %.2fs\n", (double)(clock() - tStart)/CLOCKS_PER_SEC);
}
#include <vector>
using namespace std;
struct node{
int state[16];
long long hash;
int empty_cell;
long cost;
node* parent;
int heuristic;
};
If its answer is not optimal it is because your heuristic is not admissible.
This means that sometimes it is overestimating the cost to reach a node in your graph.
linear conflicts heuristic should always be coupled with a distance estimated heuristic like Manhattan and it is not as simple as giving twice the number of linear conflicts in each row / column.
See Linear Conflict violating admissibility and driving me insane
and
https://cse.sc.edu/~mgv/csce580sp15/gradPres/HanssonMayerYung1992.pdf
I'm trying to solve this problem in C++:
"Given a sequence S of integers, find a number of increasing sequences I such that every two consecutive elements in I appear in S, but on the opposite sides of the first element of I."
This is the code I've developed:
#include<iostream>
#include<set>
#include<vector>
using namespace std;
struct Element {
long long height;
long long acc;
long long con;
};
bool fncomp(Element* lhs, Element* rhs) {
return lhs->height < rhs->height;
}
int solution(vector<int> &H) {
// set up
int N = (int)H.size();
if (N == 0 || N == 1) return N;
long long sol = 0;
// build trees
bool(*fn_pt)(Element*, Element*) = fncomp;
set<Element*, bool(*)(Element*, Element*)> rightTree(fn_pt), leftTree(fn_pt);
set<Element*, bool(*)(Element*, Element*)>::iterator ri, li;
for (int i = 0; i < N; i++) {
Element* e = new Element;
e->acc = 0;
e->con = 0;
e->height = H[i];
rightTree.insert(e);
}
//tree elements set up
ri = --rightTree.end();
Element* elem = *ri;
elem->con = 1;
elem->acc = 1;
while (elem->height > H[0]) {
Element* succ = elem;
ri--;
elem = *ri;
elem->con = 1;
elem->acc = succ->acc + 1;
}
rightTree.erase(ri);
elem->con = elem->acc;
leftTree.insert(elem);
sol += elem->acc;
// main loop
Element* pE = new Element;
for (int j = 1; j < (N - 1); j++) {
// bad case
if (H[j] < H[j - 1]) {
///////
Element* nE = new Element;
nE->height = H[j];
pE->height = H[j - 1];
rightTree.erase(nE);
leftTree.insert(nE);
///////
li = leftTree.lower_bound(pE);
long ltAcc = (*li)->acc;
li--;
///////
ri = rightTree.lower_bound(pE);
long rtAcc = 0;
if (ri != rightTree.end()) rtAcc = (*ri)->acc;
ri--;
///////
while (ri != (--rightTree.begin()) && (*ri)->height > H[j]) {
if (fncomp(*ri, *li)) {
(*li)->con = rtAcc + 1;
(*li)->acc = rtAcc + 1 + ltAcc;
ltAcc = (*li)->acc;
--li;
}
else {
(*ri)->con = ltAcc + 1;
(*ri)->acc = ltAcc + 1 + rtAcc;
rtAcc = (*ri)->acc;
--ri;
}
}
while ((*li)->height > H[j]) {
(*li)->con = rtAcc + 1;
(*li)->acc = rtAcc + 1 + ltAcc;
ltAcc = (*li)->acc;
--li;
}
(*li)->con = rtAcc + 1;
(*li)->acc = rtAcc + 1 + ltAcc;
sol += (*li)->acc;
}
// good case
else {
Element* nE = new Element;
nE->height = H[j];
ri = rightTree.upper_bound(nE);
li = leftTree.upper_bound(nE);
rightTree.erase(nE);
if (li == leftTree.end() && ri == rightTree.end()) {
nE->con = 1;
nE->acc = 1;
}
else if (li != leftTree.end() && ri == rightTree.end()) {
nE->con = 1;
nE->acc = 1 + (*li)->acc;
}
else if (li == leftTree.end() && ri != rightTree.end()) {
nE->con = (*ri)->acc + 1;
nE->acc = nE->con;
}
else {
nE->con = (*ri)->acc + 1;
nE->acc = nE->con + (*li)->acc;
}
leftTree.insert(nE);
sol += nE->acc;
}
}
// final step
li = leftTree.upper_bound(*rightTree.begin());
while (li != leftTree.end()) {
sol++;
li++;
}
sol++;
return (int)(sol % 1000000007);
}
int main(int argc, char* argv[]) {
vector<int> H = { 13, 2, 5 };
cout << "sol: " << solution(H) << endl;
system("pause");
}
The main function calls solution(vector<int> H). The point is, when the argument has the particular value of H = {13, 2, 5} the VC++ compiled program give an output value of 7 (which is the correct one), but the GNU g++ compiled program give an output value of 5 (also clang compiled program behave like this).
I'm using this website, among others, for testing different compilers
http://rextester.com/l/cpp_online_compiler_gcc
I've tried to figure out the reason for this wierd behaviour but didn't found any relevant info. Only one post treat a similar problem:
Different results VS C++ and GNU g++
and that's why I'm using long long types in the code, but the problem persists.
The problem was decrementing the start-of-sequence --rightTree.begin()
As I found VC++ and GNU g++ does not behave the same way on above operation. Here is the code that shows the difference, adapted from http://www.cplusplus.com/forum/general/84609/:
#include<iostream>
#include<set>
using namespace std;
struct Element {
long long height;
long long acc;
long long con;
};
bool fncomp(Element* lhs, Element* rhs) {
return lhs->height < rhs->height;
}
int main(){
bool(*fn_pt)(Element*, Element*) = fncomp;
set<Element*, bool(*)(Element*, Element*)> rightTree(fn_pt);
set<Element*, bool(*)(Element*, Element*)>::iterator ri;
ri = rightTree.begin();
--ri;
++ri;
if(ri == rightTree.begin()) cout << "it works!" << endl;
}
Excuse me, I have an assignment to solve the Maximum Sub Array Problem using the Brute Force Algorithm O(n^2), Divide and Conquer O(nlogn) and Kadane's Algorithm O(n). (My code is different).
"For example, for the sequence of values {−2, 1, −3, 4, −1, 2, 1, −5, 4}, the contiguous sub-array with the largest sum is [4, −1, 2, 1] with sum 6." - From the Wiki Page.
I am done with Kadane's and BruteForce, Where my required output is not just to find the sum, but also the starting index of the found sub-array and the ending index.
My current DivideAndConquer code gets me the correct sum. However, I can't see a way to keep track of my indexes since I implemented it recursively (of course). And I don't know if the only way is to use global variables in this case (I prefer not).. Can you help solve that? Or will I need to change the whole design?
#include <iostream>
int DivideAndConquer(int[], int);
int main()
{
// Example 1
//const int MyArraySize = 16;
//int MyArray[MyArraySize] = {13,-3,-25,20,-3,-16,-23,18,20,-7,12,-5,-22,15,-4,7 }; // answer: Index 7 -> 10, sum = 43
// Example 2
const int MyArraySize = 8;
int MyArray[MyArraySize] = { -2, -5, 6, -2, -3, 1, 5, -6 }; // answer: Index 2 -> 6, sum = 7
int FinalResult;
FinalResult = DivideAndConquer(MyArray, MyArraySize);
std::cout << "Using Divide And Conquer: With O(nlogn) Sum = " << FinalResult << "\n\n";
system("pause");
return 0;
}
int DivideAndConquer(int* _myArray, int _myArraySize)
{
if (_myArraySize == 1)
return _myArray[0];
int middle = _myArraySize / 2;
int Result_LeftPortion = DivideAndConquer(_myArray, middle);
int Result_RightPortion = DivideAndConquer(_myArray + middle, _myArraySize - middle);
int LeftSum = -9999;
int RightSum = -9999;
int TotalSum = 0;
for (int i = middle; i < _myArraySize; i++)
{
TotalSum += _myArray[i];
RightSum = TotalSum < RightSum ? RightSum : TotalSum;
}
TotalSum = 0;
for (int i = middle - 1; i >= 0; i--)
{
TotalSum += _myArray[i];
LeftSum = TotalSum < LeftSum ? LeftSum : TotalSum;
}
int PartialResult = LeftSum < RightSum ? RightSum : LeftSum;
int Result= (PartialResult < LeftSum + RightSum ? LeftSum + RightSum : PartialResult);
return Result;
}
Your algorithm has logical problems and it is not optimal. You are not even using the Result_LeftPortion, Result_RightPortion values. Your final result is always maximum of RightSum, LeftSum and TotalSum of the whole array. The values from all other subarrays gets ignored.
One way solve to solve this problem with divide and conquer is as follows. You should save four values for each subarray:
Maximum sum that contains the left element ( s_l )
Maximum sum that contains the right element ( s_r )
Sum of the whole array ( t )
Maximum of above values ( mx )
For the case that you are checking a subarray of size 1 all of these values are equal to the value of that element.
When merging two subarrays (sub_left, sub_right) these values will be:
s_l = max( sub_left.s_l, sub_left.t + sub_right.s_l )
s_r = max( sub_right.s_r, sub_right.t + sub_left.s_r )
t = sum( sub_left.t + sub_right.t )
mx = max( s_l, s_r, t, sub_right.mx, sub_left.mx, sub_left.r+sub_right.l)
The final result will be the value of mx of the array.
For finding the position of the subarray with maximum sum you should keep a right index and left index for each of these values and update them accordingly when you perform merge. Consider this case
sub_left.s_r range is (2,5)
sub_right.t range is (6,10)
if ( sub_right.t + sub_left.s_r > sub_right.s_r )
s_r range = (2,10)
This is my implementation:
#include <iostream>
using namespace std;
struct node {
//value, right index, left index
int value, r, l;
node(int _v, int _r, int _l){
value = _v;
r = _r;
l = _l;
}
node (){}
};
struct sub {
// max node containing left element
// max node containing right element
// total node
// max node
node s_l, s_r, t, mx;
sub ( node _l, node _r, node _t, node _mx ){
s_l = _l;
s_r = _r;
t = _t;
mx = _mx;
}
sub(){}
};
sub DivideAndConquer(int* _myArray, int left, int right)
{
if(right == left){
node n (_myArray[left],right,left);
return sub( n, n, n, n);
}
int mid = (left+right)/2;
sub sub_left = DivideAndConquer( _myArray, left, mid);
sub sub_right = DivideAndConquer( _myArray, mid+1, right);
sub cur;
if ( sub_left.t.value + sub_right.s_l.value > sub_left.s_l.value ){
cur.s_l.value = sub_left.t.value + sub_right.s_l.value;
cur.s_l.r = sub_right.s_l.r;
cur.s_l.l = sub_left.s_l.l;
} else {
cur.s_l = sub_left.s_l;
}
if ( sub_right.t.value + sub_left.s_r.value > sub_right.s_r.value ){
cur.s_r.value = sub_right.t.value + sub_left.s_r.value;
cur.s_r.l = sub_left.s_r.l;
cur.s_r.r = sub_right.s_r.r;
} else {
cur.s_r = sub_right.s_r;
}
cur.t.value = sub_right.t.value + sub_left.t.value;
cur.t.r = sub_right.t.r;
cur.t.l = sub_left.t.l;
if ( cur.s_r.value >= cur.s_l.value &&
cur.s_r.value >= cur.t.value &&
cur.s_r.value >= sub_left.mx.value &&
cur.s_r.value >= sub_right.mx.value ){
cur.mx = cur.s_r;
} else if ( cur.s_l.value >= cur.s_r.value &&
cur.s_l.value >= cur.t.value &&
cur.s_l.value >= sub_left.mx.value &&
cur.s_l.value >= sub_right.mx.value ){
cur.mx = cur.s_l;
} else if ( sub_left.mx.value >= cur.s_l.value &&
sub_left.mx.value >= cur.t.value &&
sub_left.mx.value >= cur.s_r.value &&
sub_left.mx.value >= sub_right.mx.value ){
cur.mx = sub_left.mx;
} else {
cur.mx = sub_right.mx;
}
if ( sub_left.s_r.value + sub_right.s_l.value > cur.mx.value ){
cur.mx.value = sub_left.s_r.value + sub_right.s_l.value;
cur.mx.l = sub_left.s_r.l;
cur.mx.r = sub_right.s_l.r;
}
return cur;
}
int main()
{
// Example 1
//const int MyArraySize = 16;
//int MyArray[MyArraySize] = {13,-3,-25,20,-3,-16,-23,18,20,-7,12,-5,-22,15,-4,7 }; // answer: Index 7 -> 10, sum = 43
// Example 2
const int MyArraySize = 8;
int MyArray[MyArraySize] = { -2, -5, 6, -2, -3, 1, 5, -6 }; // answer: Index 2 -> 6, sum = 7
sub FinalResult = DivideAndConquer(MyArray, 0,MyArraySize-1);
std::cout << "Sum = " << FinalResult.mx.value << std::endl;
std::cout << "( " << FinalResult.mx.l << " , " << FinalResult.mx.r << ")" << std::endl;
// system("pause");
return 0;
}
NOTE: This algorithm runs in O(n) time.
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#define MINUS_INFINITY -1e10
float Find_max_cross_subarray(int I[],float A[]){
float left_sum = MINUS_INFINITY;
float right_sum = MINUS_INFINITY;
float sum = 0;
int left_max,right_max,i;
for(i=I[2];i>=I[0];i--){
sum = sum + A[i];
if(sum > left_sum){
left_sum = sum;
left_max = i;
}
}
sum = 0;
for(i=I[2]+1;i<=I[1];i++){
sum = sum + A[i];
if(sum > right_sum){
right_sum = sum;
right_max = i;
}
}
I[0] = left_max;
I[1] = right_max;
sum = left_sum + right_sum;
return sum;
}
float Find_max_subarray(int I[],float A[]){
int sum,mid;
int left[2];
int right[2];
int cross[3];
float left_sum,right_sum,cross_sum;
if(I[0] == I[1]){
sum = A[I[0]];
}
else {
mid = floor((I[0]+I[1])/2);
left[0] = I[0];
left[1] = mid;
right[0] = mid + 1;
right[1] = I[1];
cross[0] = I[0];
cross[1] = I[1];
cross[2] = mid;
left_sum = Find_max_subarray(left,A);
right_sum = Find_max_subarray(right,A);
cross_sum = Find_max_cross_subarray(cross,A);
if((left_sum >= right_sum)&&(left_sum >= cross_sum)){
sum = left_sum;
I[0] = left[0];
I[1] = left[1];
}
else if((right_sum >= left_sum)&&(right_sum >= cross_sum)){
sum = right_sum;
I[0] = right[0];
I[1] = right[1];
}
else{
sum = cross_sum;
I[0] = cross[0];
I[1] = cross[1];
}
}
return sum;
}
int main(){
int n,i;
float max_sum;
int I[2];
float A[100] = {13, -3, -25, 20, -3,-16,-23,18,20,-7,12,-5,-22,15,-4,7};
n = sizeof(A)/sizeof(A[0]);
I[0] = 0;
I[1] = n-1;
max_sum = Find_max_subarray(I,A);
printf("Maximum sub array is A[%d ......%d] with sum %f",I[0],I[1],max_sum);
}
This is the question link - QSET - Codechef
This is the editorial link - QSET - Editorial
Basically the question queries for the number of substring in some range [L, R]. I have implemented a segment tree to solve this question. I have closely followed the editorial.
I have created a struct to represent a node of the segment tree.
Can someone explain to me how to make this program faster? I'm guessing faster I/O is the key here. Is that so?
#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#define ll long long
using namespace std;
struct stnode
{
ll ans; // the answer for this interval
ll pre[3]; // pre[i] denotes number of prefixes of interval which modulo 3 give i
ll suf[3]; // suf[i] denotes number of suffixes of interval which modulo 3 give i
ll total; // sum of interval modulo 3
void setLeaf(int value)
{
if (value % 3 == 0) ans = 1;
else ans = 0;
pre[0] = pre[1] = pre[2] = 0;
suf[0] = suf[1] = suf[2] = 0;
pre[value % 3] = 1;
suf[value % 3] = 1;
total = value % 3;
}
void merge(stnode leftChild, stnode rightChild)
{
ans = leftChild.ans + rightChild.ans;
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
if ((i + j) % 3 == 0) ans += leftChild.suf[i] * rightChild.pre[j];
pre[0] = pre[1] = pre[2] = 0;
suf[0] = suf[1] = suf[2] = 0;
for (int i = 0; i < 3; i++)
{
pre[i] += leftChild.pre[i] + rightChild.pre[(3 - leftChild.total + i) % 3];
suf[i] += rightChild.suf[i] + leftChild.suf[(3 - rightChild.total + i) % 3];
}
total = (leftChild.total + rightChild.total) % 3;
}
} segtree[400005];
void buildST(string digits, int si, int ss, int se)
{
if (ss == se)
{
segtree[si].setLeaf(digits[ss] - '0');
return;
}
long left = 2 * si + 1, right = 2 * si + 2, mid = (ss + se) / 2;
buildST(digits, left, ss, mid);
buildST(digits, right, mid + 1, se);
segtree[si].merge(segtree[left], segtree[right]);
}
stnode getValue(int qs, int qe, int si, int ss, int se)
{
if (qs == ss && se == qe)
return segtree[si];
stnode temp;
int mid = (ss + se) / 2;
if (qs > mid)
temp = getValue(qs, qe, 2 * si + 2, mid + 1, se);
else if (qe <= mid)
temp = getValue(qs, qe, 2 * si + 1, ss, mid);
else
{
stnode temp1, temp2;
temp1 = getValue(qs, mid, 2 * si + 1, ss, mid);
temp2 = getValue(mid + 1, qe, 2 * si + 2, mid + 1, se);
temp.merge(temp1, temp2);
}
return temp;
}
void updateTree(int si, int ss, int se, int index, int new_value)
{
if (ss == se)
{
segtree[si].setLeaf(new_value);
return;
}
int mid = (ss + se) / 2;
if (index <= mid)
updateTree(2 * si + 1, ss, mid, index, new_value);
else
updateTree(2 * si + 2, mid + 1, se, index, new_value);
segtree[si].merge(segtree[2 * si + 1], segtree[2 * si + 2]);
}
int main()
{
ios_base::sync_with_stdio(false);
int n, m; cin >> n >> m;
string digits; cin >> digits;
buildST(digits, 0, 0, n - 1);
while (m--)
{
int q; cin >> q;
if (q == 1)
{
int x; int y; cin >> x >> y;
updateTree(0, 0, n - 1, x - 1, y);
}
else
{
int c, d; cin >> c >> d;
cout << getValue(c-1, d-1, 0, 0, n - 1).ans << '\n';
}
}
}
I am getting TLE for larger test cases, ie subtasks 3 and 4 (check the problem page). For subtasks 1 and 2, it gets accepted.
[www.codechef.com/viewsolution/5909107] is an accepted solution. It has pretty much the same code structure except that scanf is used instead of cin. But, I turned off the sync_with_stdio so that shouldn't be a differentiator, right?
I found out what was making this program slow. In the buildST function, I pass the string digits. Since the function is recursive, and the input is fairly large, this creates many copies of the string digits thus incurring large overhead.
I declared a char digits[] at the start of the program and modified the method buildST as follows (basically same but without string digits as a parameter:
void buildST(int si, int ss, int se)
{
if (ss == se)
{
segtree[si].setLeaf(digits[ss] - '0');
return;
}
long left = 2 * si + 1, right = 2 * si + 2, mid = (ss + se) / 2;
buildST(left, ss, mid);
buildST(right, mid + 1, se);
segtree[si].merge(segtree[left], segtree[right]);
}
This solution got accepted.