环形数组/递归复杂度分析

本文介绍了如何实现环形数组,包括其核心逻辑和线程安全的优化。同时,讨论了最小栈的实现,利用两个栈保持时间复杂度为O(1)。最后,通过Master公式分析了数组最大值查找的时间复杂度,展示了递归算法的效率评估方法。
摘要由CSDN通过智能技术生成

环形数组

如何实现环形数组
思路:

  1. 使用一个putIndex和一个getIndex表示插入的位置和获取的位置,但是这样就要考虑两个指针的追赶情况,如果都是0是代表初始化还是代表已经追赶上了?
  2. 增加一个size变量 插入和获取只需要判断size大小即可
public class RingArray {
    private int[] arr;
    private int pushi;// end
    private int polli;// begin
    private int size;
    private int limit;

    public RingArray(int limit) {
        arr = new int[limit];
        pushi = 0;
        polli = 0;
        size = 0;
        this.limit = limit;
    }

    public void push(int value) {
        if (size == limit) {
            throw new RuntimeException("队列满了,不能再加了");
        }
        size++;
        arr[pushi] = value;
        pushi = nextIndex(pushi);
    }

    public int pop() {
        if (size == 0) {
            throw new RuntimeException("队列空了,不能再拿了");
        }
        size--;
        int ans = arr[polli];
        polli = nextIndex(polli);
        return ans;
    }

    public boolean isEmpty() {
        return size == 0;
    }

    // 如果现在的下标是i,返回下一个位置
    private int nextIndex(int i) {
        return i < limit - 1 ? i + 1 : 0;
    }

}

如何实现线程安全的? 提示:使用AtomicInteger原子类

最小栈

实现一个特殊的栈,在基本功能的基础上,再实现返回栈中最小元素的功能

  1. pop、 push、 getMin操作的时间复杂度都是 0(1)。
  2. 设计的栈类型可以使用现成的栈结构。

思路:使用两个栈,第二个栈记录每次的最小值

public class GetStackMin {
    private Stack<Integer> stackData;
    private Stack<Integer> stackMin;

    public GetStackMin() {
        this.stackData = new Stack<Integer>();
        this.stackMin = new Stack<Integer>();
    }

    public void push(int newNum) {
        if (this.stackMin.isEmpty()) {
            this.stackMin.push(newNum);
        } else if (newNum < this.getmin()) {
            this.stackMin.push(newNum);
        } else {
            int newMin = this.stackMin.peek();
            this.stackMin.push(newMin);
        }
        this.stackData.push(newNum);
    }

    public int pop() {
        if (this.stackData.isEmpty()) {
            throw new RuntimeException("Your stack is empty.");
        }
        this.stackMin.pop();
        return this.stackData.pop();
    }

    public int getmin() {
        if (this.stackMin.isEmpty()) {
            throw new RuntimeException("Your stack is empty.");
        }
        return this.stackMin.peek();
    }
}

Master公式

Master公式
形如
T(N)=aT(N/b) + O(N^d)(其中的a、b、d都是常数)的递归函数,可以直接通过Master公式来确定时间复杂度。aT(N/b) 是递归方法的时间复杂度
O(N^d)是递归方法之前的代码的时间复杂度
如果 log(b,a) < d,复杂度为O(N^d)
如果 log(b,a) >d,复杂度为O(N^log(b,a))
如果 log(b,a) == d,复杂度为O(N^d * logN)

案例:分析下面代码中获取数组最大值的时间复杂度

// 求arr中的最大值
	public static int getMax(int[] arr) {
		return process(arr, 0, arr.length - 1);
	}

	// arr[L..R]范围上求最大值  L ... R   N
	public static int process(int[] arr, int L, int R) {
		// arr[L..R]范围上只有一个数,直接返回,base case
		if (L == R) { 
			return arr[L];
		}
		// L...R 不只一个数
		// mid = (L + R) / 2
		int mid = L + ((R - L) >> 1); // 中点   	1
		int leftMax = process(arr, L, mid);
		int rightMax = process(arr, mid + 1, R);
		return Math.max(leftMax, rightMax);
	}

这个递归方法在递归左右两个的最大值 左边规模N/2 右边N/2 调用两次,求mid值 和 Math.max()是常数项,最终 T(N)=2*T(N/2) + O(N^0) 符合上面的公式。a = 2, b= 2, d = 0; log(2,2) > 1 则时间复杂度 = O(N^log(2,2)) = O(N)

如果修改代码为下面的

public static int process(int[] arr, int L, int R) {
        // arr[L..R]范围上只有一个数,直接返回,base case
        if (L == R) {
            return arr[L];
        }
        for (int i = 0; i < R; i++) {
            for (int j = i; j < R; j++) {
                System.out.println("");
            }
        }
        // L...R 不只一个数
        // mid = (L + R) / 2
        int mid = L + ((R - L) >> 1); // 中点   	1
        int mid2 = mid/2;
        int leftMax = process(arr, L, mid);
        int leftMax2 = process(arr, mid, mid2);
        int rightMax = process(arr, mid2, R);
        return Math.max(leftMax, rightMax);
    }

分析公式为 T(N)=3*T(N/3) + O(N^2) 最终复杂度 log(3,3) = 1 < 2
= O(N^2)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值