zoukankan      html  css  js  c++  java
  • 常见算法

    常见算法

    算法与数据结构是面试考察的重中之重,也是日后刷题时需要着重训练的部分。

    简单的总结一下,大约有这些内容:

    算法 - Algorithms

    1、排序算法:快速排序、归并排序、计数排序
    2、搜索算法:回溯、递归、剪枝技巧
    3、图论:最短路、最小生成树、网络流建模
    4、动态规划:背包问题、最长子序列、计数问题
    5、基础技巧:分治、倍增、二分、贪心

    数据结构 - Data Structures

    1、数组与链表:单/双向链表、跳舞链
    2、栈与对列
    3、树与图:最近公共祖先、并查集
    4、哈希表
    5、堆:大/小根堆、可并堆
    6、字符串:字典树、后缀树

    递归与迭代的区别

    递归(recursion):递归常被用来描述以自相似方法重复事物的过程,在数学和计算机科学中,指的是在函数定义中使用函数自身的方法。(A调用A)

    迭代(iteration):重复反馈过程的活动,每一次迭代的结果会作为下一次迭代的初始值。(A重复调用B)

    递归是一个树结构,从字面可以其理解为重复“递推”和“回归”的过程,当“递推”到达底部时就会开始“回归”,其过程相当于树的深度优先遍历。

    迭代是一个环结构,从初始状态开始,每次迭代都遍历这个环,并更新状态,多次迭代直到到达结束状态。

    # 理论上递归和迭代时间复杂度方面是一样的,但实际应用中(函数调用和函数调用堆栈的开销)递归比迭代效率要低。

    链接:https://www.jianshu.com/p/32bcc45efd32
    来源:简书

     

     

    算法的时间复杂度和空间复杂度

    • 时间复杂度和空间复杂度是用来评价算法效率高低的2个标准。

    • 时间复杂度:就是说执行算法需要消耗的时间长短,越快越好。比如你在电脑上打开计算器,如果一个普通的运算要消耗1分钟时间,那谁还会用它呢,还不如自己口算呢。

    • 空间复杂度:就是说执行当前算法需要消耗的存储空间大小,也是越少越好。本来计算机的存储资源就是有限的,如果你的算法总是需要耗费很大的存储空间,这样也会给机器带来很大的负担。

    时间复杂度的计算

    表示方法

    我们一般用“大O符号表示法”来表示时间复杂度:T(n) = O(f(n)) n是影响复杂度变化的因子,f(n)是复杂度具体的算法。

    常见的时间复杂度量级

    • 常数阶O(1)

    • 线性阶O(n)

    • 对数阶O(logN)

    • 线性对数阶O(nlogN)

    • 平方阶O(n²)

    • 立方阶O(n³)

    • K次方阶O(n^k)

    • 指数阶(2^n)

    常见的时间复杂度(按效率排序) O(1)<O(logn)<O(n)<O(nlogn)<O(n2)<O(n2logn)<O(n3)

    接下来再看一下不同的复杂度所对应的算法类型。

    img

    常数阶O(1)

    int a = 1;
    int b = 2;
    int c = 3;

    线性阶O(n)

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

    对数阶O(logN)

    int i = 1;
    while(i < n) {
       i = i * 2;
    }

    线性对数阶O(nlogN)

    for(m = 1; m < n; m++) {
       i = 1;
       while(i < n) {
           i = i * 2;
      }
    }

    平方阶O(n²)

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

    空间复杂度计算

    空间复杂度 O(1)

    如果算法执行所需要的临时空间不随着某个变量n的大小而变化,即此算法空间复杂度为一个常量,可表示为 O(1)。

    int i = 1;
    int j = 2;
    ++i;
    j++;
    int m = i + j;

    代码中的 i、j、m 所分配的空间都不随着处理数据量变化,因此它的空间复杂度 S(n) = O(1)。

    空间复杂度 O(n)

    int[] m = new int[n]
    for(i = 1; i <= n; ++i) {
      j = i;
      j++;
    }

    这段代码中,第一行new了一个数组出来,这个数据占用的大小为n,后面虽然有循环,但没有再分配新的空间,因此,这段代码的空间复杂度主要看第一行即可,即 S(n) = O(n)。

    十大经典排序算法

    # 冒泡排序
    比较相邻的元素。如果第一个比第二个大,就交换他们两个。
    对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。
    针对所有的元素重复以上的步骤,除了最后一个。
    持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
    import sys
    sys.setrecursionlimit(1000000)
    ## 冒泡排序 (******)
    ### 时间复杂度:O(n^2)
    def Bubble_sort(li):
       for i in range(len(li)-1):
           for j in range(len(li)-1-i):
               if li[j] > li[j+1]:
                   li[j], li[j+1] = li[j+1], li[j
        return li
                   
                   
    ## 选择排序
    首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置。
    再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。
    重复第二步,直到所有元素均排序完毕。
    #### 时间复杂度:O(n^2)
    def select_sort(li):
       for i in range(len(li)):
           minLoc = i ###i = 0
           for j in range(i+1, len(li)):
               if li[j] < li[minLoc]:
                   li[j], li[minLoc] = li[minLoc], li[j]
        return li
                   

    ##### 插入排序(打扑克牌)
    将第一待排序序列第一个元素看做一个有序序列,把第二个元素到最后一个元素当成是未排序序列。
    从头到尾依次扫描未排序序列,将扫描到的每个元素插入有序序列的适当位置。(如果待插入的元素与有序序列中的某个元素相等,则将待插入元素插入到相等元素的后面。)
    #### 时间复杂度: O(n^2)
    def insert_sort(li):
       for i in range(1, len(li)):
           tmp = li[i]
           j = i - 1
           while j >=0 and li[j] > tmp:
               li[j+1] = li[j]
               j = j - 1
           li[j+1] = tmp


    ## 快速排序
    1、从数列中挑出一个元素,称为 "基准"(pivot);
    2、重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作;
    3、递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序;
                                               
    def partition(li, left, right):
       tmp = li[left]
       while left < right:
           while left < right and li[right] >= tmp:
               right = right - 1
           li[left] = li[right]
           while left < right and li[left] <= tmp:
               left = left + 1
           li[right] = li[left]
       li[left] = tmp

       return left                                            
                                                                                   
    ## 时间复杂度:O(nlogn)
    def quick_sort(li, left, right):
       if left < right:
           mid = partition(li, left, right)
           quick_sort(li, left, mid-1)
           quick_sort(li, mid+1, right)
        return li
                 
                                               
    # 计算时间复杂度
    import time,random
    li = [random.randint(1,100) for _ in range(100000)]
    start = time.time()
    quick_sort(li, 0, len(li)-1)
    cost = time.time() - start
    print('quick_sort:%s' % (cost))

    import time,random
    li = [random.randint(1,100) for _ in range(100000)]
    start = time.time()
    Bubble_sort(li)
    cost = time.time() - start
    print('bubble_sort:%s' % (cost))

    import time,random
    li = [random.randint(1,100) for _ in range(100000)]
    start = time.time()
    insert_sort(li)
    cost = time.time() - start
    print('insert_sort:%s' % (cost))

    算法-力扣(LeetCode)

    链表反转

    反转一个单链表:

    输入: 1->2->3->4->5->NULL
    输出: 5->4->3->2->1->NULL  
    进阶:
    你可以迭代或递归地反转链表。你能否用两种方法解决这道题?
    # 双向指针迭代
    class Solution(object):
    def reverseList(self, head):
    """
    :type head: ListNode
    :rtype: ListNode
    """
    # 申请两个节点,pre和 cur,pre指向None
    pre = None
    cur = head
    # 遍历链表,while循环里面的内容其实可以写成一行
    # 这里只做演示,就不搞那么骚气的写法了
    while cur:
    # 记录当前节点的下一个节点
    tmp = cur.next
    # 然后将当前节点指向pre
    cur.next = pre
    # pre和cur节点都前进一位
    pre = cur
    cur = tmp
    return pre

       # 2、递归解法
       class Solution(object):
    def reverseList(self, head):
    """
    :type head: ListNode
    :rtype: ListNode
    """
    # 递归终止条件是当前为空,或者下一个节点为空
    if(head==None or head.next==None):
    return head
    # 这里的cur就是最后一个节点
    cur = self.reverseList(head.next)
    # 这里请配合动画演示理解
    # 如果链表是 1->2->3->4->5,那么此时的cur就是5
    # 而head是4,head的下一个是5,下下一个是空
    # 所以head.next.next 就是5->4
    head.next.next = head
    # 防止链表循环,需要将head.next设置为空
    head.next = None
    # 每层递归函数都返回cur,也就是最后一个节点
    return cur
       
    来源:力扣(LeetCode)

    反转字符串

    编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 char[] 的形式给出。

    示例
    输入:["h","e","l","l","o"]
    输出:["o","l","l","e","h"]

    简单实现
    class Solution:
       def reverseString(self, s):
           s.reverse()
           
    # 1、递归实现
    class Solution:
       def reverseString(self, s):
           def helper(left, right):
               if left < right:
                   s[left], s[right] = s[right], s[left]
                   helper(left + 1, right - 1)

           helper(0, len(s) - 1)
           
    # 2、一步实现
    class Solution:
       def reverseString(self, s: List[str]) -> None:
           """
          Do not return anything, modify s in-place instead.
          """
           # one step by python
           s[:] = s[::-1]
           

    来源:力扣(LeetCode)

    二叉树的最大深度

    给定一个二叉树,找出其最大深度。

    二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。

    说明: 叶子节点是指没有子节点的节点。

    示例: 给定二叉树 [3,9,20,null,null,15,7]

       3
      /
     9  20
       /  
      15   7

    方法:递归

    直观的方法是通过递归来解决问题。在这里,我们演示了 DFS(深度优先搜索)策略的示例。

    class Solution:
       def maxDepth(self,root): # root子节点
           if root is None:
               return 0
           else:
               left_height = self.maxDepth(root.left)
               right_height = self.maxDepth(root.right)
               return max(left_height,right_height)+1  #左右对比 基于子节点+1

    整数反转

    给出一个 32 位的有符号整数,你需要将这个整数中每位上的数字进行反转。

    示例:

    输入: 123
    输出: 321
    方法:字符串的反转,记录符号位。
    class Solution:
       def reverse(self, x: int) -> int:
           flag = -1 if x < 0  else 1
           res = flag * int(str(abs(x))[::-1])
           return res if (-2**31)<=res<=(2**31-1) else 0

    作者:powcai

    删除排序中数组中的重复项

    给定一个排序数组,你需要在 原地 删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。

    不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。

    示例:

    给定 nums = [0,0,1,1,1,2,2,3,3,4],

    函数应该返回新的长度 5, 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4
    你不需要考虑数组中超出新长度后面的元素。

    思路:

    用两个指针,指向第一个和第二个元素,如果他们相等,删除第二个元素。指针还指向原来的位置,继续比较。不等的话,两个指针位置都加一。遍历结束即可。

    解题思路 题意:删除有序数组重复项,把去重后的数字放在输入数组的前面 n 个位置,返回 n.

    看到题目标题的第一反应,当然是用 set !set 就是为了实现去重的。但是题目要求我们进行原地操作,并且时间复杂度是 O(1)O(1),因此就不能开辟另外的空间。

    双指针 题目需要我们把去重后的结果保存到原本的数组中,所以想到必须有一个指针指向当前需要把结果放在哪个位置。还要一个指针指向当前应该放到哪个元素。

    慢指针作为基准,快指针用于寻找与慢指针不同的元素。 如果快指针和慢指针指向的元素不等,则把快指针指向的元素放到慢指针的下一个位置。 慢指针右移,把新的元素作为基准。

    作者:fuxuemingzhu 链接:https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array/solution/fu-xue-ming-zhu-shuang-zhi-zhen-jie-fa-s-hp71/

    class Solution:
       def removeDuplicates(self, nums: List[int]) -> int:
           pre,cur=0,1 # 指针初始指向数
           while cur<len(nums):      
               if nums[pre]==nums[cur]:
                   nums.pop(cur) # 取出重复数
               else:
                   pre,cur=pre+1,cur+1  # 交换并加一往后
           return len(nums)# 数组的长度

    # 第二种解法
    class Solution(object):
       def removeDuplicates(self, nums):
           N = len(nums)
           left = 0
           for right in range(1, N):
               if nums[right] != nums[left]:
                   left += 1
                   nums[left] = nums[right]
           return left + 1

    存在重复元素

    给定一个整数数组,判断是否存在重复元素。

    如果任意一值在数组中出现至少两次,函数返回 true 。如果数组中每个元素都不相同,则返回 false

    示例:

    输入: [1,2,3,1]
    输出: true
       
    输入: [1,2,3,4]
    输出: false

    集合判断法:利用Python独有的数据类集合特性。 用nums = list(set(nums))就可以轻松排除了

    class Solution(object):
       def containsDuplicat(self,nums:list[int]) ->bool:
           if len(self(nums) == len(nums))
          return Flase
           else:
               return True
           

    只出现一次的数字

    给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。

    示例:

    输入: [4,1,2,1,2]
    输出: 4

    思路:通过数学的解法

    先通过set把数据去重,然后把所有的值相加*2去减之前的值,剩下的值就是答案

    1、数学
    class Solution(object):
       def singleNumber(self, nums):
           return 2 * sum(set(nums)) - sum(nums)
       
    2、counter函数
    from collections import Counter
    class Solution:
       def singleNumber(self, nums: List[int]) -> int:
           datas = Counter(nums)
           for each in datas:
               if datas[each] == 1: return each

    两数之和

    给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。

    你可以假设每种输入只会对应一个答案。但是,数组中同一个元素不能使用两遍。

    示例:

    给定 nums = [2, 7, 11, 15], target = 9
    因为 nums[0] + nums[1] = 2 + 7 = 9
    所以返回 [0, 1]
    #思路:两层for循环,取出值进行相加,判断是否等于target
    用两个for循环解决,注意,第二个for循环的值得是第一个的值+1
    class Solution:
       def twoSum(self, nums: List[int], target: int) -> List[int]:
           for i in range(len(nums)):
               for j in range(i+1,len(nums)):# 基于第一次之上
                   if nums[i] + nums[j] == target:
                       return [i,j]

    加一

    示例:

    输入: [1,2,3]
    输出: [1,2,4]
    解释: 输入数组表示数字 123
    class Solution(object):
       def plusOne(self, digits):
           """
          :type digits: List[int]
          :rtype: List[int]
          """
           digits_str=''
           for i in range(len(digits)):
               digits_str+=str(digits[i])
           digits_num=int(digits_str)+1
           digits_list=list(str(digits_num))
           return digits_list

    小猿取经-博客

    查找list中最大的数

    • 思路:遍历整个列表 获得对应的元素,元素与元素之间进行比较,记录最大值


    list0 = [12,45,-2,6,-9,78,99,154]
    1、max内置函数
    res=max(list0)
    print(res)

    2、for遍历比较
    max_item = list0[0]
    for item in range(0,len(list0)):
       if max_item < list0[item]:
           max_item=list0[item]
    print(max_item)

    3、for循环
    for item in list0:
       if max_item <item:
           max_item = item
    print(max_item)

    两个列表中找出相同和不相同的元素

    1、set集合去重,取交集
    list1 = [1,2,3]
    list2 = [3,4,5]
    set1 = set(list1)
    set2 = set(list2)
    print(set1&amp;set2)
    print(set1^set2)

    2、列表推导式
    list1 = [1,3,65,78]
    list2 = [1,3,8,58,78,23]
    c = [x for x in list1 if x in list2]
    b = [y for y in (list1+list2) if y not in c]
    print(c)
    print(b)

    3、for循环
    list1 = [1,3,5,8,9]
    list2 = [2,3,5,12,45]
    list3 = []
    list4 = []
    for i in list1:
       for j in list2:
           if i == j:
               list3.append(i)
    for b in (list1+list2):
       if b not in list3:
           list4.append(b)

    print(list3)
    print(list4)

    列表去重

    列表去重的几种方式
    1. for 循环去重
    list1 = [2, 1, 3, 6, 2, 1]
    temp = []
    for i in list1:
       if not i in temp:
           temp.append(i)

    2. 列表推导式去重
    list1 = [2, 1, 3, 6, 2, 1]
    temp = []
    [temp.append(i) for i in list1 if i not in temp]
    print(temp)

    3. set去重
    list1 = [2, 1, 3, 6, 2, 1]
    temp = list(set(list1))
    print(temp)
    set去重保持原来的顺序,参考5,6
    4.  使用字典fromkeys()的方法来去重
    原理是: 字典的key是不能重复的
    list1 = [2, 1, 3, 6, 2, 1]
    temp = {}.fromkeys(list1)
    print(temp)
    print(temp.keys())

    5 . 使用sort + set去重
    list1 = [2, 1, 3, 6, 2, 1]
    list2 = list(set(list1))
    list2.sort(key=list1.index)
    print(list2)

    6. 使用sorted+ set函数去重
    list1 = [2, 1, 3, 6, 2, 1]
    temp = sorted(set(list1), key=list1.index)
    print(temp)
    删除列表中的重复项
    list1 = [2, 1, 3, 6, 2, 1]
    temp = [item for item in list1 if list1.count(item) == 1]
    print(temp)

    list1 = [2, 1, 3, 6, 2, 1]
    temp = list(filter(lambda x:list1.count(x) ==1, list1))
    print(temp)

    9*9乘法表

    for row in range(1, 10):
       for col in range(1, row+1):
           print('{}*{}={}'.format(col, row, col * row), end=' ')
       print()
       
    # 左下三角九九乘法表
    for row in range(1,10): #打印行
       for col in range(1,row+1): #打印列
           print("{0}*{1}={2:2d}".format(row,col,row*col),end=" ")
    #这里是用format函数进行格式化输出控制,{2:2d}是给{2}这个位置两倍的空间,对齐乘法表
    #同时end是print函数内置方法,设置end=""print就不会进行换行操作
       print(" ") #这里是用print的特性,进行换行输出
    ————————————————

    # author : Eric
    a = 1
    sum = 0
    for i in range(1,10):
       for j in range(1,i+1):
           sum = i*j
           print("%dx%d=%d"%(i,j,sum),end="   ")
       print("")
    ————————————————
    # 一行实现
    print('n'.join([' '.join(['%s*%s=%-2s' % (y, x, x*y) for y in range(1, x+1)]) for x in range(1, 10)]))

    完数

    完数的定义:

    什么是因子? 假如整数n除以m,结果是无余数的整数 n % m == 0,那么我们称m就是n的因子.需要注意的是,唯有被除数,除数,商皆为整数,余数为零时,此关系才成立.

    什么是“完数”: 一个数如果恰好等于它的因子之和,这个数就称为”完数”。例如6=1+2+3.

    如一个数恰好等于它的因子之和,这个数就称为“完数”。

    如:6=1+2+3,请实现1000内的所有完数。

    for i in range(2,1001):   # 遍历1000以内的所有数,从2 开始
       s = i    # 把取出的数赋值给另一个变量s,用于与所有因子作差,若果减去所有的因子后结果为0,这个数即为完数。
       for j in range(1,i):    # 查找因子
           if i % j == 0:    # 找出因子
               s -= j      # 与因子作差
       if s == 0:     # 判断是否是完数
           print(i)     # 打印完数

    # 优化
    for i in range(2,1001):
       k = []   # 用于收集一个数的所有因子
       n = -1  #
       s = i  
       for j in range(1,i):
           if i % j == 0:
               n += 1
               s -= j
               k.append(j) # 收集所有因子
       
       if s == 0:
           print(i,":")   # 打印完数
           for j in range(n):   # 遍历完数的所有因子
               print(str(k[j]),end='+ ')   # 打印出所有的因子
           print(k[n]) # 打印
           
    # 方法2      
    l = [ ]
    for n in range (1,10000):
       for a in range (1,n):
           if n%a ==0:
               l.append(a)
       if sum(l)==n:
           print (l)
           print (n)
       l = []
    ————————————————

    字符串的排列组合

    给你一个字符串,比如‘abc’,请打印出该字符串的所有排列组合:

    以‘abc’为例,输出的结果应该是:'abc', 'acb', 'bac', 'bca', 'cab', 'cba'

    请用python代码编码实现:

    def fun1(s=''):
       if len(s) <= 1:
           return [s]
       else:
           sl = []
           for i in range(len(s)):
               for j in fun1(s[0:i] + s[i + 1:]):
                   sl.append(s[i] + j)
           return sl

    def main():
       a = fun1('abc')
       print(a)

    二分法查找

    def bin_search_rec(data_set, value, low, high):•    
       if low <= high:•        
           mid = (low + high) // 2•        
           if data_set[mid] == value:•            
               return mid•        
           elif data_set[mid] > value:•            
               return bin_search_rec(data_set, value, low, mid - 1)•        
           else:•            
               return bin_search_rec(data_set, value, mid + 1, high)•    
           else:•        return
           
           
     2、递归实现      
    def search(list, key):
       left = 0     # 左边界
       right = len(list) - 1   # 右边界
       while left <= right:
           mid = (left + right) // 2  # 取得中间索引
           if key > list[mid]:
               left = mid + 1
           elif key < list[mid]:
               right = mid - 1
           else:
               return mid
       else:
           return -1

    list = [2, 5, 13, 21, 26, 33, 37]
    print(search(list, 5))
    ————————————————
    原文链接:https://blog.csdn.net/weixin_42068613/java/article/details/83187817
       
    3、    
    def binary_search(list, item):
       low = 0  # (以下2行)low和high用于跟踪要在其中查找的列表部分
       high = len(list) - 1
       n = 0
       while low <= high:  # 只要范围没有缩小到只包含一个元素
           n += 1
           mid_1 = (low + high)/2  # 就检查中间的元素
           mid = int(mid_1)
           guess = list[mid]
           if guess == item:  # 找到了元素
               return "要猜的数字在列表中的索引号为%d,共猜了%d次"%(mid,n)
           if guess > item:  # 猜的数字大了
               high = mid -1
           else:  # 猜的数字小了
               low = mid + 1
       return "没有这个数"  # 没有指定的元素


    my_list = []
    for i in range(1, 201):
       my_list.append(i)
    print(my_list)

    print(binary_search(my_list, 100))
    print(binary_search(my_list, 111))

    #运行结果

    [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200]
    要猜的数字在列表中的索引号为99,共猜了1次
    要猜的数字在列表中的索引号为110,共猜了8次

    Process finished with exit code 0

    两个数组的交集 II

    简单地利用数组操作,一次循环就能找出结果。

    class Solution:
       def intersect(self, nums1: List[int], nums2: List[int]) -> List[int]:
           res = []
           for i, num in enumerate(nums1):
               if num in nums2:
                   res.append(num)
                   nums2.pop(nums2.index(num))
           return res

    来源:力扣(LeetCode)

    合并两个有序的链表

    将两个升序链表合并为一个新的升序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。

    示例:

    输入:1->2->4, 1->3->4
    输出:1->1->2->3->4->4

    # Definition for singly-linked list.
    # class ListNode:
    #     def __init__(self, x):
    #         self.val = x
    #         self.next = None

    class Solution:
       def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode:
           if not l1: return l2  # 终止条件,直到两个链表都空
           if not l2: return l1
           if l1.val <= l2.val:  # 递归调用
               l1.next = self.mergeTwoLists(l1.next,l2)
               return l1
           else:
               l2.next = self.mergeTwoLists(l1,l2.next)
               return l2
           

    移除元素

    给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。

    不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。

    元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。

    思路 有的同学可能说了,多余的元素,删掉不就得了。

    要知道数组的元素在内存地址中是连续的,不能单独删除数组中的某个元素,只能覆盖。

    暴力解法 这个题目暴力的解法就是两层for循环,一个for循环遍历数组元素 ,第二个for循环更新数组。

    删除过程如下:

    很明显暴力解法的时间复杂度是O(n^2),这道题目暴力解法在leetcode上是可以过的。

    作者:carlsun-2 链接:https://leetcode-cn.com/problems/remove-element/solution/dai-ma-sui-xiang-lu-27-yi-chu-yuan-su-ba-du7k/

    class Solution:
       def removeElement(self, nums: List[int], val: int) -> int:
           i,n = 0,len(nums)
           for j in range(n):
               if nums[j] != val:
                   nums[i] = nums[j]
                   i += 1
           return i

    作者:carlsun-2
    链接:https://leetcode-cn.com/problems/remove-element/solution/dai-ma-sui-xiang-lu-27-yi-chu-yuan-su-ba-du7k/
    来源:力扣(LeetCode)

    搜索插入位置

    给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。

    你可以假设数组中无重复元素。

    示例 1:

    输入: [1,3,5,6], 5
    输出: 2

    示例 2:

    输入: [1,3,5,6], 2
    输出: 1

    解题思路 思路: 1.二分法查找 2.查完后nums[mid]肯定是和target最接近的,所以只需要比较它和target的大小来确定target的位置 注意: 返回坐标那里容易出错,注意nums[mid]大于target时,nums[mid]后移,target占据nums[mid]原来的位置,所以返回的应该是mid

    作者:FvHk1D0CCe 链接:https://leetcode-cn.com/problems/search-insert-position/solution/python-er-fen-fa-by-fvhk1d0cce-paje/

    class Solution:
       def searchInsert(self, nums: List[int], target: int) -> int:
           low,high = 0,len(nums)-1
           while low <= high:
               mid = (low + high) // 2
               if nums[mid] == target:
                   return mid
               elif nums[mid] < target:
                   low = mid + 1
               elif nums[mid] > target:
                   high = mid -1

           #print(mid,nums[mid])

           if nums[mid] > target: #注意,是target替换nums[mid]的位置
               return mid

           return mid + 1


    作者:FvHk1D0CCe
    链接:https://leetcode-cn.com/problems/search-insert-position/solution/python-er-fen-fa-by-fvhk1d0cce-paje/
    来源:力扣(LeetCode)

    最后一个单词的长度

    给你一个字符串 s,由若干单词组成,单词之间用空格隔开。返回字符串中最后一个单词的长度。如果不存在最后一个单词,请返回 0 。

    单词 是指仅由字母组成、不包含任何空格字符的最大子字符串。

    来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/length-of-last-word示例 1:

    输入:s = "Hello World"
    输出:5

    示例 2:

    输入:s = " "
    输出:0
    class Solution:
       def lengthOfLastWord(self, s: str) -> int:
           x = s.split(' ')
           for i in x[::-1]:
               if i != '':
                   return len(i)
           return 0

    删除排序链表中的重复元素

    存在一个按升序排列的链表,给你这个链表的头字节点head,请删除所有重复的元素,使每个元素只出现一次。

    返回同样按升序排列的结果链表。

    示例 1:

    img

    输入:head = [1,1,2]
    输出:[1,2]

    解题思路 题意:在一个有序链表中,链表中的值重复的节点仅保留一个。

    重点:有序链表,所以,一个节点的值出现不止一次,那么它们必相邻。

    下面使用两种方法 :递归,迭代。其中迭代又分为两种方法。

    作者:fuxuemingzhu 链接:https://leetcode-cn.com/problems/remove-duplicates-from-sorted-list/solution/fu-xue-ming-zhu-di-gui-die-dai-4-chong-d-t3bp/

    class Solution(object):
       def deleteDuplicates(self, head):
           if not head: return None
           prev, cur = head, head.next
           while cur:
               if cur.val == prev.val:
                   prev.next = cur.next
               else:
                   prev = cur
               cur = cur.next
           return head


    作者:fuxuemingzhu
    链接:https://leetcode-cn.com/problems/remove-duplicates-from-sorted-list/solution/fu-xue-ming-zhu-di-gui-die-dai-4-chong-d-t3bp/
    • 时间复杂度:O(N)O(N),对链表每个节点遍历了一次;

    • 空间复杂度:O(1)O(1),只使用了常量的空间。

    根据字符出现的频率排序

    给定一个字符串,请将字符串里的字符按照出现的频率降序排列

    示例 1:

    输入: "tree"

    输出: "eert"

    解释: 'e'出现两次,'r'和't'都只出现一次。 因此'e'必须出现在'r'和't'之前。此外,"eetr"也是一个有效的答案。

    思路一:直接排序 首先遍历字符串,用哈希表记录每个字符出现的次数 然后获取哈希表中的键值对,根据value进行降序排列 遍历排列后的结果,将字符根据其出现次数加到最终结果res中去

    作者:edelweisskoko 链接:https://leetcode-cn.com/problems/sort-characters-by-frequency/solution/451-gen-ju-zi-fu-chu-xian-pin-lu-pai-xu-xup3z/ 来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

    class Solution:
       def frequencySort(self, s: str) -> str:
           count = {}
           for c in s:
               count[c] = count.get(c, 0) + 1
           items = [(-val, key) for key, val in count.items()]
           res = ""
           for val, key in sorted(items):
               res += key * (-val)
           return res

    作者:edelweisskoko
    链接:https://leetcode-cn.com/problems/sort-characters-by-frequency/solution/451-gen-ju-zi-fu-chu-xian-pin-lu-pai-xu-xup3z/
    来源:力扣(LeetCode)
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

     

    剑指 Offer 58 - I. 翻转单词顺序

    输入一个英文句子,翻转句子中单词的顺序,但单词内字符的顺序不变。为简单起见,标点符号和普通字母一样处理。例如输入字符串"I am a student. ",则输出"student. a am I"。

    例子:

    示例 1:

    输入: "the sky is blue" 输出: "blue is sky the" 示例 2:

    输入: " hello world! " 输出: "world! hello" 解释: 输入字符串可以在前面或者后面包含多余的空格,但是反转后的字符不能包括。

    来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/fan-zhuan-dan-ci-shun-xu-lcof示例 1:

    class Solution:
       def reverseWords(self, s: str) -> str:
           s = s.strip() # 删除首尾空格
           i = j = len(s) - 1
           res = []
           while i >= 0:
               while i >= 0 and s[i] != ' ': i -= 1 # 搜索首个空格
               res.append(s[i + 1: j + 1]) # 添加单词
               while s[i] == ' ': i -= 1 # 跳过单词间空格
               j = i # j 指向下个单词的尾字符
           return ' '.join(res) # 拼接并返回

    作者:jyd
    链接:https://leetcode-cn.com/problems/fan-zhuan-dan-ci-shun-xu-lcof/solution/mian-shi-ti-58-i-fan-zhuan-dan-ci-shun-xu-shuang-z/
    来源:力扣(LeetCode)
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

    剑指 Offer 38. 字符串的排列

    输入一个字符串,打印出该字符串中字符的所有排列。

    你可以以任意顺序返回这个字符串数组,但里面不能有重复元素。

    示例:

    输入:s = "abc" 输出:["abc","acb","bac","bca","cab","cba"]

    限制:

    1 <= s 的长度 <= 8

    来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/zi-fu-chuan-de-pai-lie-lcof 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

    class Solution:
       def permutation(self, s: str) -> List[str]:
           c, res = list(s), []
           def dfs(x):
               if x == len(c) - 1:
                   res.append(''.join(c))   # 添加排列方案
                   return
               dic = set()
               for i in range(x, len(c)):
                   if c[i] in dic: continue # 重复,因此剪枝
                   dic.add(c[i])
                   c[i], c[x] = c[x], c[i]  # 交换,将 c[i] 固定在第 x 位
                   dfs(x + 1)               # 开启固定第 x + 1 位字符
                   c[i], c[x] = c[x], c[i]  # 恢复交换
           dfs(0)
           return res

    作者:jyd
    链接:https://leetcode-cn.com/problems/zi-fu-chuan-de-pai-lie-lcof/solution/mian-shi-ti-38-zi-fu-chuan-de-pai-lie-hui-su-fa-by/
    来源:力扣(LeetCode)
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

     

  • 相关阅读:
    MTK 关闭耳机调至最大音量时,提示损伤听力
    MTK LCM的添加
    chmod chown
    ubuntu14.04设置静态IP
    MTK NTP和NITZ更新时间的问题
    Rk3288 双屏异显单触摸
    MTK 修改默认时区
    MTK 屏幕旋转90度
    MTK WIFI底部加入返回按钮
    MTK 自定义按键添加广播
  • 原文地址:https://www.cnblogs.com/Gaimo/p/14918059.html
Copyright © 2011-2022 走看看