算法何时可以具有平方根(n)时间复杂度?

时间:2015-10-18 06:16:48

标签: time-complexity

有人能给我一个具有平方根(n)时间复杂度的算法的例子。平方根时间复杂度甚至意味着什么?

6 个答案:

答案 0 :(得分:19)

  • 平方根时间复杂度意味着算法需要O(N^(1/2))评估,其中输入的大小为N.
  • 作为花费O(sqrt(n))时间的算法的示例,Grover的算法需要花费很长时间。 Grover's algorithm是一种量子算法,用于在O(sqrt(n))时间内搜索n个条目的未排序数据库。
  • 让我们举一个例子来了解如果出现问题,我们如何才能达到O(sqrt(N))运行时复杂性。这将是详细的,但有趣的是要理解。 (以下示例,在回答此问题的上下文中,取自Coding Contest Byte: The Square Root Trick,非常有趣的问题和有趣的技巧,以达到O(sqrt(n))复杂度)

    • 给定A,包含n个元素数组,实现点更新和范围求和查询的数据结构。

      • update(i,x) - > A [i]:= x(点更新查询)
      • 查询(lo,hi) - >返回A [lo] + A [lo + 1] + .. + A [hi]。 (范围总和查询)
    • 天真的解决方案使用数组。更新(数组索引访问)需要O(1)时间,范围总和需要O(hi - lo) = O(n)(从开始索引到结束索引迭代并累加)。

    • 更有效的解决方案是将数组拆分为长度为k的切片,并将切片总和存储在数组S中。
    • 更新需要持续时间,因为我们必须更新A的值和相应S的值。在更新(6,5)中,我们必须将A [6]更改为5,这会导致更改值S 1使S保持最新状态。 Updating element
    • 范围和查询很有趣。第一个和最后一个切片的元素(部分包含在查询范围内)必须逐个遍历,但对于完全包含在我们范围内的切片,我们可以直接使用S中的值并获得性能提升。 Range-sum query
    • 在查询(2,14)中,我们得到了
 query(2, 14) = A[2] + A[3]+ (A[4] + A[5] + A[6] + A[7]) + (A[8] + A[9] + A[10] + A[11]) + A[12] + A[13] + A[14] ; 
 query(2, 14) = A[2] + A[3] + S[1] + S[2] + A[12] + A[13] + A[14] ;
 query(2, 14) = 0 + 7 + 11 + 9 + 5 + 2 + 0;
 query(2, 14) = 34;
  • 更新和查询的代码是:
  def update(S, A, i, k, x):
      S[i/k] = S[i/k] - A[i] + x
      A[i] = x
  def query(S, A, lo, hi, k):
      s = 0
      i = lo
      //Section 1 (Getting sum from Array A itself, starting part)
      while (i + 1) % k != 0 and i <= hi:
          s += A[i]
          i += 1
      //Section 2 (Getting sum from Slices directly, intermediary part)
      while i + k <= hi:
          s += S[i/k]
          i += k
      //Section 3 (Getting sum from Array A itself, ending part)
      while i <= hi:
          s += A[i]
          i += 1
  return s
  • 现在让我们确定复杂性。
  • 每个查询都取平均值
    • 第1节平均需要k / 2次。 (你可以迭代至少k / 2)
    • 第2节平均花费n / k时间,基本上是切片数
    • 第3节平均需要k / 2次。 (你可以迭代至少k / 2)
    • 所以,总的来说,我们得到k / 2 + n / k + k / 2 = k + n / k时间。
  • 并且,对于k = sqrt(n),这是最小化的。 sqrt(n)+ n / sqrt(n)= 2 * sqrt(n)
  • 因此我们得到O(sqrt(n))时间复杂度查询。

答案 1 :(得分:4)

有很多情况。 这些是根(n)复杂性可以解决的少数问题[也可能更好]。

  • 查找数字是否为素数。
  • Grover算法:允许在未分类输入上搜索(在量子上下文中)与输入大小的平方根成比例的时间。link
  • 数字的因式分解。

您将面临许多需要使用sqrt(n)复杂性算法的问题。

作为第二部分的答案:

sqrt(n)复杂度意味着if the input size to your algorithm is n then there approximately sqrt(n) basic operations ( like **comparison** in case of sorting). Then we can say that the algorithm has sqrt(n) time complexity.

让我们分析第三个问题,这一点很清楚。

let's n= positive integer. Now there exists 2 positive integer x and y such that
     x*y=n;
     Now we know that whatever be the value of x and y one of them will be less than sqrt(n). As if both are greater than sqrt(n) 
  x>sqrt(n) y>sqrt(n) then x*y>sqrt(n)*sqrt(n) => n>n--->contradiction.

因此,如果我们检查2到sqrt(n)那么我们将考虑所有因素(1和n是微不足道的因素)。

代码段:

   int n;
   cin>>n;
   print 1,n;
   for(int i=2;i<=sqrt(n);i++) // or for(int i=2;i*i<=n;i++)
     if((n%i)==0)
       cout<<i<<" ";

注意:您可能认为不考虑重复,我们也可以通过从1循环到n来实现上述行为。是的,但是谁想要运行一个可以在O(n)中的O(sqrt(n))中运行的程序。我们总是寻找最好的。

阅读Cormen一书算法简介

我还会请求您阅读以下stackoverflow问题和答案,他们会清除所有疑问:)

  1. Are there any O(1/n) algorithms?
  2. Plain english explanation Big-O
  3. Which one is better?
  4. How do you calculte big-O complexity?

答案 2 :(得分:4)

素数

正如其他一些答案中所提到的,与素数相关的一些基本事物需要O(sqrt(n))时间:

  1. 查找除数的数量
  2. 查找除数之和
  3. 找到Euler的小孩
  4. 下面我提到两种先进的算法,它们的复杂性也带有sqrt(n)项。

    MO&#39>算法

    尝试此问题:Powerful array

    我的解决方案:

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 1E6 + 10, k = 500;
    
    struct node {
        int l, r, id;
        bool operator<(const node &a) {
            if(l / k == a.l / k) return r < a.r;
            else return l < a.l;
        }
    } q[N];
    
    long long a[N], cnt[N], ans[N], cur_count;
    void add(int pos) {
        cur_count += a[pos] * cnt[a[pos]];
        ++cnt[a[pos]];
        cur_count += a[pos] * cnt[a[pos]];
    }
    void rm(int pos) {
        cur_count -= a[pos] * cnt[a[pos]];
        --cnt[a[pos]];
        cur_count -= a[pos] * cnt[a[pos]];
    }
    
    int main() {
        int n, t;
        cin >> n >> t;
        for(int i = 1; i <= n; i++) {
            cin >> a[i];
        }
        for(int i = 0; i < t; i++) {
            cin >> q[i].l >> q[i].r;
            q[i].id = i;
        }
        sort(q, q + t);
        memset(cnt, 0, sizeof(cnt));
        memset(ans, 0, sizeof(ans));
    
        int curl(0), curr(0), l, r;
        for(int i = 0; i < t; i++) {
            l = q[i].l;
            r = q[i].r;
    
    /* This part takes O(n * sqrt(n)) time */
            while(curl < l)
                rm(curl++);
            while(curl > l)
                add(--curl);
            while(curr > r)
                rm(curr--);
            while(curr < r)
                add(++curr);
    
            ans[q[i].id] = cur_count;
        }
        for(int i = 0; i < t; i++) {
            cout << ans[i] << '\n';
        }
        return 0;
    }
    

    查询缓冲

    尝试此问题:Queries on a Tree

    我的解决方案:

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 2e5 + 10, k = 333;
    
    vector<int> t[N], ht;
    int tm_, h[N], st[N], nd[N];
    inline int hei(int v, int p) {
        for(int ch: t[v]) {
            if(ch != p) {
                h[ch] = h[v] + 1;
                hei(ch, v);
            }
        }
    }
    inline void tour(int v, int p) {
        st[v] = tm_++;
        ht.push_back(h[v]);
        for(int ch: t[v]) {
            if(ch != p) {
                tour(ch, v);
            }
        }
        ht.push_back(h[v]);
        nd[v] = tm_++;
    }
    
    int n, tc[N];
    vector<int> loc[N];
    long long balance[N];
    vector<pair<long long,long long>> buf;
    inline long long cbal(int v, int p) {
        long long ans = balance[h[v]];
        for(int ch: t[v]) {
            if(ch != p) {
                ans += cbal(ch, v);
            }
        }
        tc[v] += ans;
        return ans;
    }
    inline void bal() {
        memset(balance, 0, sizeof(balance));
        for(auto arg: buf) {
            balance[arg.first] += arg.second;
        }
        buf.clear();
        cbal(1,1);
    }
    
    int main() {
        int q;
        cin >> n >> q;
        for(int i = 1; i < n; i++) {
            int x, y; cin >> x >> y;
            t[x].push_back(y); t[y].push_back(x);
        }
        hei(1,1);
        tour(1,1);
        for(int i = 0; i < ht.size(); i++) {
            loc[ht[i]].push_back(i);
        }
        vector<int>::iterator lo, hi;
        int x, y, type;
        for(int i = 0; i < q; i++) {
            cin >> type;
            if(type == 1) {
                cin >> x >> y;
                buf.push_back(make_pair(x,y));
            }
            else if(type == 2) {
                cin >> x;
                long long ans(0);
                for(auto arg: buf) {
                    hi = upper_bound(loc[arg.first].begin(), loc[arg.first].end(), nd[x]);
                    lo = lower_bound(loc[arg.first].begin(), loc[arg.first].end(), st[x]);
                    ans += arg.second * (hi - lo);
                }
                cout << tc[x] + ans/2 << '\n';
            }
            else assert(0);
    
            if(i % k == 0) bal();
        }
    }
    

答案 3 :(得分:0)

原始性测试

JavaScript解决方案

def obtenerTexto(frame):
    #here i have the text always
    h, w, c = imagen.shape
    hini = int(0.84*h)
    wfin = int(0.45*w)
    text = frame[hini:h, 0:wfin]
    #resize the imagen and i make a threshold
    resize = cv2.resize(im, None,fx=2, fy=2, interpolation = cv2.INTER_CUBIC)
    gray = cv2.cvtColor(resize, cv2.COLOR_BGR2GRAY)
    retval, chat = cv2.threshold(gray,150,255,cv2.THRESH_BINARY)
    #pytesseract
    textoNuevo = pytesseract.image_to_string(chat).split("\n")

#Video Capture
video_file = 'videos/Video.flv'
cap = cv2.VideoCapture(video_file)

# Properties
font = cv2.FONT_HERSHEY_SIMPLEX
font_scale = 0.6
color = (0,255,0)
thickness = 2
height_prop = cv2.CAP_PROP_FRAME_HEIGHT
fps_prop = cv2.CAP_PROP_FPS

while(cap.isOpened()):

    ret, frame = cap.read()
    if ret == True:
        # Text position   
        height = int(cap.get(height_prop))
        position = (50, height - 50)  
        # Frames per second
        fps = "{0:.2f}".format(cap.get(fps_prop))
        text = "FPS: " + fps
        # Put text
        cv2.putText(frame, text, position, font, font_scale, color, thickness)
        # Serching text and OCR
        obtener_texto(frame)
        # Display
        height , width , layers =  frame.shape
        new_h=int(height/2)
        new_w=int(width/2)
        resize = cv2.resize(frame, (new_w, new_h))
        cv2.imshow("Video", resize)
        # Exit?
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
    else:
        break

# Release everything if job is finished
cap.release()
cv2.destroyAllWindows()

复杂度

O(N ^ 1/2)因为对于给定的n值,您只需要查找n是否可以被2整除为根。

答案 4 :(得分:0)

JS原始性测试

O( sqrt n ))

感谢Samme Bae,该版本的性能更高,能给我带来启发。 ?

function isPrime(n) {
  if (n <= 1)
      return false;
  if (n <= 3)
      return true;

  // Skip 4, 6, 8, 9, and 10
  if (n % 2 === 0 || n % 3 === 0)
      return false;

  for (let i = 5; i * i <= n; i += 6) {
      if (n % i === 0 || n % (i + 2) === 0)
          return false;
  }
  return true;
}

isPrime(677);

答案 5 :(得分:0)

此链接为O(\sqrt{n})(即O(sqrt n)时间复杂度)提供了非常基本的初学者理解。这是视频中的最后一个示例,但我建议您观看整个视频。

https://www.youtube.com/watch?v=9TlHvipP5yA&list=PLDN4rrl48XKpZkf03iYFl-O29szjTrs_O&index=6

视频中O(\sqrt{n})的最简单示例,即O(sqrt n)时间复杂度算法为:

p = 0;

for(i = 1; p <= n; i++)
{
    p = p + i;
}

先生。 Abdul Bari以对数据结构和算法的简单解释而闻名。