Блог пользователя kllp

Автор kllp, 13 лет назад, По-английски

Today I was having troubles remembering how to code ternary search for integers. Through the ages, people have been taught to divide the interval into three equal length parts. Fortunately Sisu told me that I should not... I believe this is a new thing for some people.

while(lo < hi) {
    int mid = (lo + hi) >> 1;
    if(f(mid) > f(mid+1)) {
        hi = mid;
    }
    else {
        lo = mid+1;
    }
}
  • Проголосовать: нравится
  • +53
  • Проголосовать: не нравится

»
13 лет назад, скрыть # |
 
Проголосовать: нравится -27 Проголосовать: не нравится

Have you ever heard about binary search?

  • »
    »
    13 лет назад, скрыть # ^ |
     
    Проголосовать: нравится +40 Проголосовать: не нравится

    You'd normally use binary search for finding an element from an increasing sequence of values, and ternary search for finding the maximum when the values first increase and then start decreasing at some point.

    The observation here is that you can replace ternary search with a binary search for the point when the sign between adjacent values change. This is of course a simple thing, but in many places you can find the recommended solution being ternary search, which is harder to get right and less efficient.

»
13 лет назад, скрыть # |
 
Проголосовать: нравится +8 Проголосовать: не нравится

Does it work correctly in case f(mid) == f(mid + 1) ?

For example: f = {0, 1, 0, 0, 0}

»
13 лет назад, скрыть # |
 
Проголосовать: нравится +8 Проголосовать: не нравится

Btw, if you search for some "double" answer, there is another intresting way to do that: just divide the segment by golden ratio, for example: AB → ACDB, where C divides AB in the way that AC < CB and D divides AB and AD > DB. The feature is unaware of the sub-segment you choose (AD or CB), one of the points you need on the next step is C or D; it's easy to prove from the definition of golden ratio.

So, you have to calculate only one next func value instead of two, but that can be really important in some cases, for example ones the function I minimized contained Dijkstra algorithm, so that was a cool cheat and my code easily passed TL without optimizing anything else.

»
13 лет назад, скрыть # |
 
Проголосовать: нравится +16 Проголосовать: не нравится

What you're doing is very similar to binary search on continuous derivative (which may be useful for some floating-point problems, because calculating derivative may be performed with more precision sometimes). If it is below zero until some point and is above zero after that point, then local optima is in the point where derivative is zero. You've calculated discrete derivative and look for a point where it changes the sign.

»
13 лет назад, скрыть # |
 
Проголосовать: нравится 0 Проголосовать: не нравится

So, what you are saying is that in some cases you can just use binary instead of ternary? I couldn't understand it well. Would you mind linking me to a problem where this applies?

Thanks in advance!

  • »
    »
    13 лет назад, скрыть # ^ |
     
    Проголосовать: нравится 0 Проголосовать: не нравится

    no, he's not saying that. what he means is that it is sufficient to divide the interval [lo,hi] into two parts, instead of three, while doing ternery search.
    the benefit is the reduction in complexity from to . this is usually not significant, but it's a reduction nonetheless and may help for problems with tight time limits.

»
11 лет назад, скрыть # |
← Rev. 2  
Проголосовать: нравится 0 Проголосовать: не нравится

I don't need to take any special care with the f(mid+1)? If the search goes to the end of the data in my array for example. Actually i just got Accepted with this approach for ternary search by changing it to:

int ternary(int lo, int hi){
	while(lo <= hi){
		int mid = (lo+hi) >> 1;
		if(f(mid) > f(mid+1)){
			hi = mid-1;
		}
		else{
			lo = mid+1;
		}
	}
}
  • »
    »
    8 лет назад, скрыть # ^ |
     
    Проголосовать: нравится 0 Проголосовать: не нравится

    If we look at it from a divide and conquer perspective, you are discarding mid at every iteration, I don't understand how this got accepted.

    The safe thing to to do with this approach is to keep a variable which keeps the maximum value of the mid.

    If f(mid)>f(mid+1), maybe the mid value found at first iteration is the actual maxima. Now you've reduced search space to [lo,mid-1] regardless. You can just add a line max_val = max(max_val,f(mid)) above it, to make it absolutely correct.

    You don't need to worry about mid+1 exceeding high in the author's code, here you've added an extra equal-to lo<**=**high , so you should take care of it.

»
11 лет назад, скрыть # |
 
Проголосовать: нравится 0 Проголосовать: не нравится

Hi . I have got a great help from this Blog about Ternary Search . And I have applied in some problems also and got a predicted result . Now My Question is how can I use this Ternary Search for Floating Point Data ??

Thanks in advance .

»
8 лет назад, скрыть # |
 
Проголосовать: нравится +9 Проголосовать: не нравится

There's a better way: Golden-section search. It reduces hi - lo by a factor of φ ≈ 1.618 by only probing one new point. For example, it can reduce 106 to 1 in around 29 calls to f, instead of 40.

»
8 лет назад, скрыть # |
 
Проголосовать: нравится 0 Проголосовать: не нравится

But it doesn't work for the case f(mid)=f(mid+1)