算法题-数组相关

最长递增子序列

    public static void main(String[] args) throws Exception {
        int[] nums = {1, 3, 4, 2, 2};
        int len = nums.length;
        if (len == 0) {
            return;
        }
        int dp[] = new int[len];
        dp[0] = 1;
        int maxAns = 1;
        for (int i = 1; i < len; i++) {
            dp[i] = 1;
            for (int j = 0; j < i; j++) {
                if (nums[i] > nums[j]) {
                    dp[i] = Math.max(dp[i], dp[j] + 1);
                }
            }
            maxAns = Math.max(dp[i], maxAns);
        }
        System.out.println(maxAns);
    }

寻找重复数

示例 1:
输入:nums = [1,3,4,2,2]
输出:2
快慢指针法

class Solution {
    public int findDuplicate(int[] nums) {
        int slow = 0, fast = 0;
        do {
            slow = nums[slow];
            fast = nums[nums[fast]];
        } while (slow != fast);
        slow = 0;
        while (slow != fast) {
            slow = nums[slow];
            fast = nums[fast];
        }
        return slow;
    }
}

除自身以外数组的乘积

class Solution {
    public int[] productExceptSelf(int[] nums) {
        int length = nums.length;
        int[] answer = new int[length];

        // answer[i] 表示索引 i 左侧所有元素的乘积
        // 因为索引为 '0' 的元素左侧没有元素, 所以 answer[0] = 1
        answer[0] = 1;
        for (int i = 1; i < length; i++) {
            answer[i] = nums[i - 1] * answer[i - 1];
        }

        // R 为右侧所有元素的乘积
        // 刚开始右边没有元素,所以 R = 1
        int R = 1;
        for (int i = length - 1; i >= 0; i--) {
            // 对于索引 i,左边的乘积为 answer[i],右边的乘积为 R
            answer[i] = answer[i] * R;
            // R 需要包含右边所有的乘积,所以计算下一个结果时需要将当前值乘到 R 上
            R *= nums[i];
        }
        return answer;
    }
}

数组中的第K个最大元素

乘积最大子数组

    public static void main(String[] args) throws Exception {
        int[] nums = {2,3,-2,4,-1,5};
        int maxF = nums[0],minF = nums[0],ans = nums[0];
        int length = nums.length;
        for(int i=1;i<length;i++){
            int mx = maxF, mn = minF;
            maxF = Math.max(mx*nums[i],Math.max(mn*nums[i],nums[i]));
            minF = Math.min(mn*nums[i], Math.min(mx*nums[i], nums[i]));
            ans = Math.max(maxF,ans);
        }
        System.out.println(ans);
    }

颜色分类

示例 1:
输入:nums = [2,0,2,1,1,0]
输出:[0,0,1,1,2,2]

    public static void sortColors(int[] nums) {
        int n = nums.length;
        int l = 0, r = n - 1;
        for (int i = 0; i <= r; i++) {
            // 右指针r存2
            while (i <= r && nums[i] == 2) {
                int temp = nums[i];
                nums[i] = nums[r];
                nums[r] = temp;
                r--;
            }
            // 左指针l存0
            if (nums[i] == 0) {
                int temp = nums[i];
                nums[i] = nums[l];
                nums[l] = temp;
                l++;
            }
        }
    }

最长连续序列

哈希法

    public static void main(String[] args) throws Exception {
        int[] temperatures = {4, 5, 6, 7, 0, 1, 2};
        Set<Integer> set = new HashSet<>();
        for (int a : temperatures) {
            set.add(a);
        }
        int longLen = 0;
        for (int b : temperatures) {
            if (!set.contains(b - 1)) {
                int currNum = b;
                int currLen = 1;
                while (set.contains(currNum + 1)) {
                    currNum += 1;
                    currLen += 1;
                }
                longLen = Math.max(longLen, currLen);
            }
        }
        System.out.println(longLen);/**/
    }

在排序数组中查找元素的第一个和最后一个位置

二分法

在这里插入代码片

搜索旋转排序数组

    public static void main(String[] args) throws Exception {

        int[] temperatures = {4, 5, 6, 7, 0, 1, 2};
        int target = 4;
        int s = search(temperatures, target);
        System.out.println(s);
    }
public static int search(int[] nums, int target) {
        int len = nums.length;
        if (len == 0) {
            return -1;
        }
        if (len == 1) {
            return nums[0] == target ? 0 : 1;
        }
        int l = 0, r = len - 1;
        if (l < r) {
            int mid = (r + l) / 2;
            if (nums[mid] == target) {
                return mid;
            }
            if (nums[0] <= nums[mid]) {
                if (target < nums[mid] && target >= nums[0]) {
                    r = mid - 1;

                } else {
                    l = mid + 1;
                }
            } else {
                if (target >= nums[mid] && target < nums[mid]) {
                    l = mid + 1;
                } else {
                    r = mid - 1;
                }
            }
        }
        return -1;
    }

三数之和等于0

给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有满足条件且不重复的三元组。

注意:答案中不可以包含重复的三元组。

    public static void main(String[] args) throws Exception {
        int[] temperatures = {-1, -2, -3, 0, 5, 4, 1, 3, 2};
        Arrays.sort(temperatures);
        int len = temperatures.length;
        List<Integer> lists = new ArrayList<>();
        for (int first = 0; first < len; first++) {
            if (temperatures[first] >= 0) {
                break;
            }
            if (first > 0 && temperatures[first] == temperatures[first - 1]) {
                continue;
            }
            int second = first + 1;
            int last = len - 1;
            while (second < last) {
                if (second > first + 1 && temperatures[second] == temperatures[second - 1]) {
                    second++;
                    continue;
                }
                if (last < len - 1 && temperatures[last] == temperatures[last + 1]) {
                    last--;
                    continue;
                }
                int sum = temperatures[first] + temperatures[last] + temperatures[second];
                if (sum == 0) {
                    lists.add(temperatures[first]);
                    lists.add(temperatures[second]);
                    lists.add(temperatures[last]);
                    second++;
                    last--;
                } else if (sum > 0) {
                    last--;
                } else {
                    second++;
                }
            }
        }
        lists.stream().forEach(item -> System.out.println(item));
    }
def threeSum(nums):

    # 定义一个空列表存储结果
    alist = []
    # 如果列表的长度小于2或者=None, 直接停止执行
    if nums is None or len(nums) < 2:
        return alist
    # 排序后再找数据
    nums.sort()
    for i in range(len(nums)-2):
        # 如果当前值>0,有序列表后面的值相加肯定都大于0,所有直接退出循环
        if nums[i] > 0:
            break
        # 如果当前值和前面的值相等,会导致结果重复,所以应该跳过
        if i > 0 and nums[i] == nums[i-1]:
            continue
        # l指向i后的第一个元素,称为左指针
        l = i + 1
        # r指向列表最后一个元素,称为右指针
        r = len(nums) - 1
        while l < r:
            sum = nums[i] + nums[l] + nums[r]
            if sum == 0:
                alist.append((nums[i], nums[l], nums[r]))
                # 如果左指针当前的值和下一个值相同,会导致重复,所以跳过
                while l < r and nums[l] == nums[l + 1]:
                    l += 1
                # 如果右指针当前的值和前一个值相同,会导致重复,所以跳过
                while l > r and nums[r] == nums[r - 1]:
                    r -=1
                l += 1
                r -= 1
            # 如果三个数的和大于0,说明右指针所指的值太大
            elif sum > 0:
                r -= 1
            # 如果三个数的和小于0,说明左指针所指的值太小
            else:
                l += 1
    return alist

if __name__ == '__main__':
    nums = [-1, 2, -1,-2,0,2,-1]
    print(threeSum(nums))

盛最多水的容器

给你 n 个非负整数 a1,a2,…,an,每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0) 。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
说明:不能倾斜容器。

暴力法

    public static void main(String[] args) throws Exception {
        int[] temperatures = {1, 8, 6, 2, 5, 4, 8, 3, 7};
        int len = temperatures.length;
        int max = 0;
        for(int i=0;i<len-1;i++){
            for(int j=i+1;j<len;j++){
                int temp = Math.min(temperatures[i],temperatures[j])*(j-i);
                if(temp>max){
                    max = temp;
                }
            }
        }
        System.out.println(max);
    }

双指针法

    public static void main(String[] args) throws Exception {
        int[] temperatures = {1, 8, 6, 2, 5, 4, 8, 3, 7};
        int len = temperatures.length;
        int ans = 0;
        int left = 0;
        int right = len - 1;
        while (left < right) {
            int temp = Math.min(temperatures[left], temperatures[right]) * (right - left);
            if (temp > ans) {
                ans = temp;
            }
            if (temperatures[left] <= temperatures[right]) {
                left++;
            } else {
                right--;
            }
        }
        System.out.println(ans);
    }

每日温度

请根据每日 气温 列表 temperatures ,请计算在每一天需要等几天才会有更高的温度。如果气温在这之后都不会升高,请在该位置用 0 来代替。

在这里插入代码片

获取生成数组中的最大值

    public static void main(String[] args) throws Exception {
        int n = 6;
        if (n == 0) {
            return;
        }
        int[] s = new int[n + 1];
        s[1] = 1;
        for (int i = 2; i < n + 1; i++) {
            s[i] = s[i / 2] + i % 2 * s[i / 2 + 1];
        }
        System.out.println(Arrays.stream(s).max().getAsInt());
    }

找到所有数组中消失的数字

    public static void main(String[] args) throws Exception {
        int[] a = {1,7,9};
        int l = a.length;
        List<Integer> collect = Arrays.stream(a).boxed().collect(Collectors.toList());
        List<Integer> ins = new ArrayList<>();
        for(int i=1;i<=l;i++){
            if(!collect.contains(i)){
                ins.add(i);
            }
        }
        ins.stream().forEach(item-> System.out.println(item));
    }

移动零

    public static void main(String[] args) throws Exception {
        int[] a = {0, 1, 0, 3, 12};
        int left = 0;
        int right = 0;
        while (right < a.length) {
            if (a[right] != 0) {
                a[left] = a[right];
                left++;
            }
            right++;
        }
        while (left < a.length) {
            a[left] = 0;
            left++;
        }

        Arrays.stream(a).forEach(item -> System.out.println(item));
    }

方法1:空间局部优化
统计0的个数;定义一个新列表,把非空的元素放前面,0放后面

def moveZeros(nums):
    zero_num = 0
    new_list = []
    for i in range(len(nums)):
        if nums[i] ==0:
            zero_num += i
        else:
            new_list.append(nums[i])

    for i in range(zero_num):
        new_list.append(0)

    for i in range(len(nums)):
        nums[i] = new_list[i]
nums = [1, 2, 4, 0 ,4 ,8 ,0]
moveZeros(nums)
print(nums)

方法2::空间最优,操作局部优化(双指针)
非空元素往前移,剩下的位置填0

def moveZeroes(nums) :
    lastNonZeroFoundAt = 0

    for i in range(len(nums)):
        if nums[i] != 0 :
            nums[lastNonZeroFoundAt] = nums[i]
            lastNonZeroFoundAt += 1
        i += 1

    for i in range(lastNonZeroFoundAt, len(nums)):
        nums[i] = 0
nums = [1,3,0,4,0,2]
moveZeroes(nums)
print(nums)

多数元素

给定一个大小为 n 的数组,找到其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。

    int[] a = {2,2,1,1,1,2,2};
    Arrays.sort(a);
    System.out.println(a[a.length/2]);

只出现一次的数字

一个整型数组 nums 里除两个数字之外,其他数字都出现了两次。请写程序找出这两个只出现一次的数字。
要求时间复杂度是O(n),空间复杂度是O(1)。
位运行

class Solution {
    public int singleNumber(int[] nums) {
        int single = 0;
        for (int num : nums) {
            single ^= num;
        }
        return single;
    }
}
        int[] nums = {4, 1, 2, 1, 2};
        Set<Integer> set = new HashSet<>();
        for(int i=0;i<nums.length;i++){
            if(!set.add(nums[i])){
                set.remove(nums[i]);
            }
        }
        System.out.println(set.toArray()[0]);
def singleNumber(alist):
    no_duplicate_list = []
    for i in alist:
        if i not in no_duplicate_list:
            no_duplicate_list.append(i)
        if i in no_duplicate_list:
            no_duplicate_list.remove(i)
    return  no_duplicate_list.pop()

方法2:哈希操作

def singleNumber(nums):
    hash_table = {}
    for i in nums:
        try:
            hash_table.pop(i)
        except:
            hash_table[i] =1
    return hash_table.popitem()[0]

方法3:数学

def singleNumber( nums):
    return 2*sum(set(nums)) - sum(nums)
nums = [1,2,1,2,3]
print(singleNumber(nums))

买卖股票的最佳时机

    public static void main(String[] args) throws Exception {
        int[] nums = {7, 1, 5, 3, 6, 4};
        int minprice = Integer.MAX_VALUE;
        int maxprofit = 0;
        for (int i = 0; i < nums.length; i++) {
            if (nums[i] < minprice) {
                minprice = nums[i];
            } else if (maxprofit < nums[i] - minprice) {
                maxprofit = nums[i] - minprice;
            }
        }
        System.out.println(maxprofit);
    }
def maxProfit(prices):
    min_price = prices[0]
    max_profit = 0
    for i in range(1, len(prices)):
        max_profit = max(max_profit, prices[i]-min_price)
        min_price = min(prices[i], min_price)
    return max_profit

m =  [7,1,5,3,6,4]
r = maxProfit(m)
print(r)

买卖股票的最佳时机 II

def maxProfit(prices):
    maxprofit = 0
    for i in range(1, len(prices)):
        if prices[i] > prices[i-1]:
            maxprofit += prices[i] - prices[i-1]
    return maxprofit

prices = [1,2,3,4,5]
mp = maxProfit(prices)
print(mp)

丢失的数字

给定一个包含 0, 1, 2, …, n 中 n 个数的序列,找出 0 … n 中没有出现在序列中的那个数。
示例 1:
输入: [3,0,1]
输出: 2

def missingNumber(nums):
    expected_sum = len(nums)*(len(nums)+1)//2
    actual_sum = sum(nums)
    return expected_sum -actual_sum

存在重复元素

方法1:线性遍历

def contains_duplicate(nums):
    for i in range(1, len(nums)):
        for j in range(0, i):
            if nums[j] == nums[i]:
                return True
    return False

nums = [1,2,3,4,3,2]
contains_duplicate(nums)

方法2:排序

def contains_duplicate(nums):
    nums.sort()
    i = 0
    while i < len(nums):
        if nums[i] == nums[i+1]:
            return True
        i += 1
    return False
nums = [1,2,3,3,2]
s = contains_duplicate(nums)
print(s)

方法3:哈希
利用支持快速搜索和插入操作的动态数据结构。

import collections
def contains_duplicate(nums):
    t = collections.Counter(nums)
    for i in nums:
        if t[i]>1:
            return True
    return False

nums = [1,2,3,3,2]
s = contains_duplicate(nums)
print(s)

方法4:利用set

def contains_duplicate(nums):
    return True if len(set(nums)) != len(nums) else False
nums = [1,2,3,3,2]
s = contains_duplicate(nums)
print(s)

最大子序和

    public static void main(String[] args) throws Exception {
        int[] nums = {-2, 1, -3, 4, -1, 2, 1, -5, 4};
        int pre = 0, maxAns = nums[0];
        for(int x: nums){
            pre = Math.max(pre+x, x);
            maxAns = Math.max(maxAns, pre);
        }
        System.out.println(maxAns);
    }
class Solution:
    def cross_sum(self, nums, left, right, p):
        if left == right:
            return nums[left]
        left_subsum = float('-inf')
        curr_sum = 0
        for i in range(p, left - 1, -1):
            curr_sum += nums[i]
            left_subsum = max(left_subsum, curr_sum)
        right_subsum = float('-inf')
        curr_sum = 0
        for i in range(p + 1, right + 1):
            curr_sum += nums[i]
            right_subsum = max(right_subsum, curr_sum)
        return left_subsum + right_subsum

    def helper(self, nums, left, right):
        if left == right:
            return nums[left]
        p = (left + right) // 2
        left_sum = self.helper(nums, left, p)
        right_sum = self.helper(nums, p + 1, right)
        cross_sum = self.cross_sum(nums, left, right, p)
        return max(left_sum, right_sum, cross_sum)

    def maxSubArray(self, nums: 'List[int]') -> 'int':
        return self.helper(nums, 0, len(nums) - 1)

方法2:贪心
算法:
该算法通用且简单:遍历数组并在每个步骤中更新:
当前元素
当前元素位置的最大和
迄今为止的最大和

class Solution:
    def maxSubArray(self, nums: 'List[int]') -> 'int':
        n = len(nums)
        curr_sum = max_sum = nums[0]

        for i in range(1, n):
            curr_sum = max(nums[i], curr_sum + nums[i])
            max_sum = max(max_sum, curr_sum)
            
        return max_sum

方法3:动态规划(Kadane 算法)
常数空间,沿数组移动并在原数组修改。

def maxSubArray(nums):
    n = len(nums)
    max_sum = nums[0]
    for i in range(1, n):
        if nums[i-1]>0:
            nums[i] += nums[i-1]
        max_sum = max(nums[i], max_sum)
    return max_sum

nums = [-1,2,3,5,3,-9]
s = maxSubArray(nums)
print(s)

删除排序数组中的重复项

给定一个排序数组,你需要在 原地 删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。
不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。

def removeDuplicates(nums):
    n = len(nums)
    if n == 0:
        return 0
    l = 0
    for r in range(1, n):
        if nums[r] != nums[l]:
            l += 1
            nums[l] = nums[r]
    return l + 1

nums = [-1,2,3,5,3,-9]
s = removeDuplicates(nums)
print(s)

两数之和等于目标值

给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。
你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。

示例:
给定 nums = [2, 7, 11, 15], target = 9
因为 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]
java解法:

    public static void main(String[] args) {
        int[] nums = new int[]{12, 36, 19, 1, 25, 48, 22, 87, 92};
        int[] s = twoSum(nums, 68);
        if(s!=null) {
            System.out.println(Arrays.toString(s));
        }
    }
// 暴力解法
public static int[] twoSum(int[] nums, int target){
    for(int i=0; i<nums.length-1; i++){
        for(int j=i+1; j<nums.length; j++){
            if(nums[i]+nums[j] == target){
                return new int[]{nums[i], nums[j]};
            }
        }
    }
    return null;
}

// 先排序,定义左右指针
public static int[] twoSum(int[] nums, int target){
       Arrays.sort(nums);
       int i =0;
       int j = nums.length-1;
       while (true) {
           if(i>=j){
               return null;
           }
           if (nums[i]+nums[j]==target)
               return new int[]{nums[i], nums[j]};
           if(nums[i]+nums[j] < target) {
               i++;
               continue;
           }
           if(nums[i]+nums[j] > target) {
               j--;
               continue;
           }
       }
    }
    
// 建立hashMap映射(面试写法)
    public static int[] twoSum(int[] nums, int target){
        Map<Integer, Integer> map= new HashMap<>();
        for(int i=0; i<nums.length; i++){
            map.put(nums[i], i);
        }
        for(int i =0; i<nums.length; ){
            int t = target - nums[i];
            if(map.containsKey(t) && map.get(t) != i){
                return new int[]{nums[i], t};
            }
        }
        return null;
    }
    
    // 建立hashMap映射,合并两个for(没有排序,先找到哪个值都可以)
    public static int[] twoSum(int[] nums, int target){
        Map<Integer, Integer> map= new HashMap<>();
        for(int i =0; i<nums.length; i++){
            int t = target - nums[i];
            if(map.containsKey(t) && map.get(t) != i){
                return new int[]{nums[i], t};
            }
            map.put(nums[i], i);
        }
        return null;
    }

python解法

// 建立hashMap映射
class Solution(object):
    def twoSum(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: List[int]
        """
        hashmap = {}
        for k, v in enumerate(nums):
            hashmap[v] = k
        for k,v in enumerate(nums):
            j = hashmap.get(target-v)
            if j is not None and j != k:
                return [k, j]

冒泡排序

比较相邻的两个元素,如果第一个比第二个大就交换位置,循环完一遍最后的位置就是最大值。依次类推
时间复杂度O(n^2)
稳定性:稳定

def test(n):
    m = len(n)
    for i in range(m-1):
        for j in range(m-i-1):
            if n[j] > n[j+1]:
                n[j], n[j+1] = n[j+1], n[j]
    print(n)
a = [8,7,6,5,3,4,2,1]
test(a)
排序效果:
[7, 6, 5, 3, 4, 2, 1, 8]
[6, 5, 3, 4, 2, 1, 7, 8]
[5, 3, 4, 2, 1, 6, 7, 8]
[3, 4, 2, 1, 5, 6, 7, 8]
[3, 2, 1, 4, 5, 6, 7, 8]
[2, 1, 3, 4, 5, 6, 7, 8]
[1, 2, 3, 4, 5, 6, 7, 8]

冒泡排序优化

def bubbleSort(nums):
    l = len(nums)
    k = l-1
    # 记录最小值的位置
    n = 0
    for i in range(l-1):
        # 记录交换元素的位置
        pos = 0
        # 记录交换元素的次数
        flag = 0
        # 遍历找到最大值
        for j in range(n, k):
            if nums[j] > nums[j+1]:
                nums[j], nums[j+1] = nums[j+1], nums[j]
                # 只要有交换元素,flag就设置为1
                flag = 1
                # 每次有元素交换,就记录最后一次交换的位置
                pos = j
            #  如果没有交换元素,说明已经排序
        if flag == 0:
            return
        # pos之后的元素已排好序,不需要再遍历
        k = pos
        # 反向遍历找到最小值
        for j in range(n+1, k):
            if nums[j] < nums[j-1]:
                nums[j], nums[j-1] = nums[j-1],nums[j]
                flag =1
        n += 1
        if flag ==0:
            return
nums = [1,2,3]
bubbleSort(nums)
print(nums)

选择排序

先找最小值放到第一个位置,找第二个小值放到第二个位置,依次类推。
时间复杂度O(n^2),不稳定

def test(alist):
    # 将最小的最放在最前面
    length = len(alist)
    for i in range(length-1):
        temp = i
        for j in range(i+1, length):
            if alist[j] < alist[temp]:
                temp = j
        alist[i], alist[temp] =alist[temp], alist[i]
    return alist
alist = [4,6,5,7,3,2,1]  
print(test(alist))
排序效果:
[1, 6, 5, 7, 3, 2, 4]
[1, 2, 5, 7, 3, 6, 4]
[1, 2, 3, 7, 5, 6, 4]
[1, 2, 3, 4, 5, 6, 7]
[1, 2, 3, 4, 5, 6, 7]
[1, 2, 3, 4, 5, 6, 7]   

插入排序

假设前面是值是有序列表,将后面的值插到前面的有序列表中,依次类推
时间复杂度O(n^2) ,稳定性:稳定

def insert_sort(a):
    for i in range(1, len(a)):
        for j in range(i, 0, -1):
            if a[j] < a[j - 1]:
                a[j],a[j-1] = a[j-1],a[j]
            else:
                break
        print(a)
a = [4,6,5,7,2,5,2]
insert_sort(a)
排序效果:
[4, 6, 5, 7, 2, 5, 2]
[4, 5, 6, 7, 2, 5, 2]
[4, 5, 6, 7, 2, 5, 2]
[2, 4, 5, 6, 7, 5, 2]
[2, 4, 5, 5, 6, 7, 2]
[2, 2, 4, 5, 5, 6, 7]

希尔排序

希尔排序是插入排序的改进版。

def shell_sort(alist):
    n = len(alist)
    # gap 是间隔
    gap = n//2
    while gap > 0 :
        # 插入算法
        for i in range(gap, n):
            j= i
            while j>0:
                if alist[j] <alist[j-gap]:
                    alist[j],alist[j-gap] = alist[j-gap],alist[j]
                else:
                    break
        gap = gap//2

a = [1,3,2,65,32,54,87]
shell_sort(a)
print(a)

快速排序

找出序列中的第一个值,判断这个值在序列中的位置。判断方法这个值前的元素都比这个值小,这个值后的元素都比这个值大。依次类推
最优时间复杂度:O(nlogn),最坏时间复杂度O(n^2),不稳定

def quick_sort(alist, start, end):
    # 只有一个元素时不执行
    if start >= end:
        return
    mid_value = alist[start]
    low = start
    high = end
    while low < high:
        # high游标左移
        while low < high and alist[high] >=  mid_value:
            high -= 1
        alist[low] = alist[high]
        # low游标右移
        while low < high and alist[low] < mid_value :
            low += 1
        alist[high] = alist[low]

    # 找到元素的位置并放置
    alist[low] = mid_value

    # 对Low左边的列表进行排序
    quick_sort(alist, start, low-1)
    # 对Low右边的列表进行排序
    quick_sort(alist, low+1, end)

a = [78,67,111,8,112,70,45]
quick_sort(a,0,len(a)-1)
print(a)

归并排序

时间复杂度O(nlogn),稳定性:稳定

def merge_sort(alist):
    n = len(alist)
    if n <=1:
        return alist
    mid = n//2
    # left  采用归并排序后生成新的列表
    left_li = merge_sort(alist[:mid])
    # right  采用归并排序后生成新的列表
    right_li = merge_sort(alist[mid:])

    # 将两个列表排序后合并成新的列表
    left_pointer, right_pointer = 0, 0
    result = []
    while left_pointer < len(left_li) and right_pointer < len(right_li):
        if left_li[left_pointer] > right_li[right_pointer]:
            result.append(right_li[right_pointer])
            right_pointer += 1
        else:
            result.append(left_li[left_pointer])
            left_pointer += 1
    result += left_li[left_pointer:]
    result += right_li[right_pointer:]
    return result

a = [11,32,43,12,5,38,34]
rs = merge_sort(a)
print(rs)

二分查找

前提:列表有序,时间复杂度O(logn)

def binary_search(alist, item):
    n = len(alist)
    if n <= 0:
        return False
    mid = n//2
    if item == alist[mid]:
        return True
    if item <alist[mid]:
        return binary_search(alist[:mid], item)
    elif item > alist[mid]:
        return binary_search(alist[mid+1:], item)

你可能感兴趣的:(技术类,算法,算法)