数据结构与算法(10):排序相关

数据结构与算法(10):排序相关

本次内容主要是LeetCode sort tags下的题目的解法和思路,基础排序方法并没有在此记录,但可能会直接用在相关题目,以下是记录,题号与LeetCode对应。

题目1:922. Sort Array By Parity II

Given an array A of non-negative integers, half of the integers in A are odd, and half of the integers are even.
Sort the array so that whenever A[i] is odd, i is odd; and whenever A[i] is even, i is even.
You may return any answer array that satisfies this condition.
image.png

"""
方法1 :新建了一个列表,偶(奇)数存在新列表偶(奇)数下标。
    time : O(n)
    space: O(n)
方法2 :无需建表,偶(奇)数不在偶(奇)数下标,交换它们的值。
    time : O(n)
    space: O(1)
"""
class Solution(object):
    def sortArrayByParityII(self, A):
        """
        :type A: List[int]
        :rtype: List[int]
        """
        
        # method 1:
        # if not A:
        #     return None
        # res = [0]*len(A)
        # i, j = 0, 1
        # for ch in A:
        #     if ch % 2 == 0:
        #         res[i] = ch
        #         i += 2
        #     else:
        #         res[j] = ch
        #         j += 2
        # return res
        
        # method 2:
        if not A:
            return None
        i, j = 0, 1
        n = len(A)
        while i < n and j < n:
            if A[i] % 2 == 0:
                i += 2
            elif A[j] % 2 == 1:
                j += 2
            elif A[i] % 2 == 1 and A[j] % 2 == 0:
                A[i], A[j] = A[j], A[i] 
                i += 2
                j += 2
        return A
题目2:976. Largest Perimeter Triangle

Given an array A of positive lengths, return the largest perimeter of a triangle with non-zero area, formed from 3 of these lengths.
If it is impossible to form any triangle of non-zero area, return 0.
image.png

"""
思路:
要返回的是最大的周长,我们可以对A先排序,然后从大到小判决是否满足构成三角形的条件
如果满足a + b > c( a-b<c 已经满足,因为排序好了),则返回a+b+c
如果循环结束还未找到满足条件的a,b,c,则返回0
"""
class Solution(object):
    def largestPerimeter(self, A):
        """
        :type A: List[int]
        :rtype: int
        """
        
        # method 1:
        A = sorted(A)[::-1]
        for i in range(len(A) - 2):
            if A[i] < A[i + 1] + A[i + 2]:
                return A[i] + A[i + 1] + A[i + 2]
        return 0
题目3:973. K Closest Points to Origin

We have a list of points on the plane. Find the K closest points to the origin (0, 0)
(Here, the distance between two points on a plane is the Euclidean distance.)
You may return the answer in any order. The answer is guaranteed to be unique (except for the order that it is in.)
image.png

"""
方法1:
    0.计算出每一个点到原点的距离,放在distance中,同时保存其在points中的位置
    1.对distance按距离从小到大排序(python内置排序方法timsort)
    2.res保存distance前K位对应的坐标,并返回
    
    时间复杂度O(nlogn)
方法2:
    堆排序...
    时间复杂度O(nlogK)
"""
class Solution(object):
    def kClosest(self, points, K):
        """
        :type points: List[List[int]]
        :type K: int
        :rtype: List[List[int]]
        """
        
        #method 1 Timsort
        distance = []
        res = []
        for i,point in enumerate(points):
            distance.append([point[0]**2 + point[1]**2, i])
        distance = sorted(distance,key=lambda x:x[0])
        for i in range(K):
            res += [points[distance[i][1]]]
        return res
    
        #method 2: heap sort
        # return heapq.nsmallest(K, points, lambda (x, y): x * x + y * y)
题目4:969. Pancake Sorting

Given an array A, we can perform a pancake flip: We choose some positive integer k <= A.length, then reverse the order of the first k elements of A. We want to perform zero or more pancake flips (doing them one after another in succession) to sort the array A.
Return the k-values corresponding to a sequence of pancake flips that sort A. Any valid answer that sorts the array within 10 * A.length flips will be judged as correct.
image.png

"""
煎饼排序的思想:
    1.首先是找到未排序序列的最大值(未包括排好的部分),翻转最大值之前(包括最大值)的序列,这时最大值到了第一位,然后再翻转整个未排序的序列,最大值到了末尾。
    2.记录 已排序的数字个数(在表末尾的数)
    3.未排好的序列在整个序列的前部分,对这部分跳转到步骤1
    注:中心思想,要把最大的数放到最后表尾,必须先把它放到表头,然后再翻到表尾。
    注:此题还要求,返回其翻转的位置,用res列表记录即可。
    
    参考:http://blog.jobbole.com/74263/
"""
class Solution(object):
    def pancakeSort(self, A):
        """
        :type A: List[int]
        :rtype: List[int]
        """
        
        # 煎饼排序
        
        res = []
        done = 0 
        n = len(A)
        
        while sorted(A) != A: #未按从小到大序时,一直执行以下排序方法
            
            lstToCheck = A[0:n - done] # 未排好序的段
            indOfLargest = A.index(max(lstToCheck)) # 获得该段最大值的下标
            
            # 每次最大值之前全部翻转,后面不变
            A = A[:indOfLargest + 1][::-1] + A[indOfLargest + 1:] 
            res.append(indOfLargest + 1) # 翻转的位置
            
            # 未排序的部分全部翻转,把最大的翻大盘后面去
            A[:n - done] = A[:n - done][::-1]
            res.append(n - done) # 翻转的位置
            
            done += 1 #记录排序好了多少个了,即A后半部分已经排好的大的数的个数
        return res #返回翻转位置的列表
题目5:524. Longest Word in Dictionary through Deleting

Given a string and a string dictionary, find the longest string in the dictionary that can be formed by deleting some characters of the given string. If there are more than one possible results, return the longest word with the smallest lexicographical order. If there is no possible result, return the empty string.
image.png

"""
方法1:
    0.要返回的是在s中能经由删除某些字符构成的最长的单词,我们可以先对d排序
    1.按长度长的放前面,相同长度时按字典序
    2.之后我们再遍历d中的单词,判断其是否可由s删除某些字符构成,一旦发现,直接返回
    3.若遍历完还没发现,则按要求返回空串
    
    
    复杂度分析:定义len(s) = n ,len(d) = m 
    T(m,n) = max( O(nlogn) + O(mn) ) 排序 + 判断
    最优O(mn) = O(n),第一个就找到,那么复杂度取O(nlogn)
    最差,最后一个才找到,或者找不到,那么复杂度O(mn)
    
方法2:
    与方法1类似,只不过不先对d排序,而是直接遍历,用res字符串保存最长且字典序小的
    在找到一个新的满足条件的单词时,需要和保存在res中的比较,取长度长的那个,长度相同,取字典序小的那个。
    
    时间复杂度O(mn)
    
"""
class Solution(object):
    def findLongestWord(self, s, d):
        """
        :type s: str
        :type d: List[str]
        :rtype: str
        """
        
        # method 1
        d.sort(key = lambda x: (-len(x), x)) #按长度逆序,长度相同按字典序
        
        #遍历判断单词是否可由s删除某些字符构成
        for word in d:
            i = 0
            for c in s:
                if i < len(word) and word[i] == c:
                    i += 1
            if i == len(word):
                return word #因为长度从大到小排序,第一个满足的就是最长的
        return "" # 若找不到,返回空字符串

        # method 2
    
        # res = ''
        # #遍历判断单词是否可由s删除某些字符构成
        # for word in d:
        #     i = 0
        #     for c in s:
        #         if i < len(word) and word[i] == c:
        #             i += 1
        #     if i == len(word):
        #         if i > len(res):
        #             res = word
        #         elif i == len(res):
        #             res = min(res,word)
        #         else:
        #             pass      
        # return res 
题目6:75. Sort Colors

Given an array with n objects colored red, white or blue, sort them in-place so that objects of the same color are adjacent, with the colors in the order red, white and blue.
Here, we will use the integers 0, 1, and 2 to represent the color red, white, and blue respectively.
Note: You are not suppose to use the library’s sort function for this problem.
image.png

"""
荷兰国旗问题:快速排序特殊情况的变种,时间复杂度O(n)



中心思想是用三个指针,把序列分成前中后三段,把0放到第一段,把2放到第三段,1不动,自然就放在中间段。
begin,end,cur 三个指针,begin指向第一段的段尾(前面的都是0),end指向第三段的段头(后面的都是2),cur从下标0开始遍历,如果cur == end,说明已经排序好。

http://www.cnblogs.com/gnuhpc/archive/2012/12/21/2828166.html
https://www.cnblogs.com/junyuhuang/p/4390780.html
"""
class Solution(object):
    def sortColors(self, nums):
        """
        :type nums: List[int]
        :rtype: None Do not return anything, modify nums in-place instead.
        """
        
                
        red, white, blue = 0, 0, len(nums)-1
    
        while white <= blue:
            if nums[white] == 0:
                nums[red], nums[white] = nums[white], nums[red]
                white += 1
                red += 1
            elif nums[white] == 1:
                white += 1
            else:
                nums[white], nums[blue] = nums[blue], nums[white]
                blue -= 1
题目7:767. Reorganize String

Given a string S, check if the letters can be rearranged so that two characters that are adjacent to each other are not the same.
If possible, output any possible result. If not possible, return the empty string.
image.png

"""
此题突破点在于:
    如果想要不出现重复字符,串S中某个字母的次数不能大于 m = len(S)//2.
    一旦某个字母x频次大于m,则假设把m个x间隔放在奇数下标,则偶数下标处还需放置x,出现相邻重复
    反过来,任意字母频次不大于m,则一定可以间隔排出不出现相邻重复的顺序。
    
    排序方法:
    先对S按字母频次排序,取前m个放在奇数位,后m个依次插入到偶数位
    
    1.假设字母最大频次>m,则一定会在某个位置出现xx(即当前位置与前一位置字母相同),返回 ""
    2.假设字母最大频次=m,则把x插入奇数位,其它插入偶数位,比不出现相邻重复字母
    3.假设字母最大频次<m,则把前m位插入奇数位,其余插入偶数位,也不出现相邻重复(因为按频次排序,后面的字母频次少于前面的,在奇数位已经消耗了一部分,偶数位该字母到达不了相邻位置)
    
    所以,2和3是返回reorganize string的情况,和一起就行,1是返回空串的情况
"""
class Solution(object):
    def reorganizeString(self, S):
        """
        :type S: str
        :rtype: str
        """
        
        # method 1
        
        #按频次从大道小排序
        a = sorted(sorted(S), key=S.count)
        
        #前半部分间隔排序到奇数下标处;后半部分插入到偶数下标处
        h = len(a) // 2
        a[1::2], a[::2] = a[:h], a[h:]
        
        #把list转换成str返回
        res = a[0]
        for x in a[1:]:
            if x != res[-1]:
                res += x
            else: # if x=res[-1],means xx mode in res, return ""
                return ""
        return res 
题目8:147. Insertion Sort List

Sort a linked list using insertion sort.

"""
插入的操作分为三种情况:
    1.如果当前值大于等于已排序段段尾的值,段尾后移一位(相当于把当前值插入到段尾)
    2.如果当前值小于段首,直接把当前值插入到段首之前,并把段首更新到当前节点
    3.如果当前值大于等于段首值且小于段位值,则遍历这段值,把当前值插入合适位置。
    
    注:由于链表不能往前遍历,所以第三种情况,需要从段首开始遍历,但不能直接用head =head.next去遍历,否则会因此丢失段首位置,所以我们用q来遍历,维持head不变
    最后返回head即可。
    
    时间复杂度: O(n^2)
    while p.next遍历为O(n),1和2为常数时间复杂度,3的比较次数为1至n-1,所以总的时间复杂度为 O(n^2),和数组的插入排序一样。
"""

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

class Solution(object):
    def insertionSortList(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        if not head: #空链表情况
            return None
        p = head
        while p.next: #p遍历所有元素
            if p.next.val >= p.val: #直接插入到已排序段后面
                p = p.next
            elif p.next.val < head.val: #插入到已排序段段首,并更新段首
                tempnode = p.next
                p.next = p.next.next
                tempnode.next = head
                head = tempnode
            else: # p.next.val >= head.val and p.next.val < p.val 
            #插入到已排序段段首和段尾之间 合适 的位置,用q来向后遍历,因为head要维持不变。
                q = head
                while p.next.val >= q.next.val: #遍历,比较大小
                    q = q.next
                tempNode = p.next
                p.next = p.next.next
                tempNode.next = q.next
                q.next = tempNode
        return head 
        
        # p = dummy = ListNode(0)
        # cur = dummy.next = head
        # while cur and cur.next:
        #     val = cur.next.val
        #     if cur.val < val:
        #         cur = cur.next
        #         continue
        #     if p.next.val > val:
        #         p = dummy
        #     while p.next.val < val:
        #         p = p.next
        #     new = cur.next
        #     cur.next = new.next
        #     new.next = p.next
        #     p.next = new
        # return dummy.next
题目9:56. Merge Intervals

Given a collection of intervals, merge all overlapping intervals.
image.png

# Definition for an interval.
# class Interval(object):
#     def __init__(self, s=0, e=0):
#         self.start = s
#         self.end = e

"""
此题关键在于,对intervals按起始点start排序,然后遍历,如果某个start小于前一位的end,则把前面的end改为max(前一end,当前end)
"""
class Solution(object):
    def merge(self, intervals):
        """
        :type intervals: List[Interval]
        :rtype: List[Interval]
        """
        out = []
        intervals = sorted(intervals, key=lambda x: x.start)
        for i in intervals:
            if out and i.start <= out[-1].end:
                out[-1].end = max(out[-1].end, i.end)
            else:
                out += i,
        return out
题目10:274. H-Index

Given an array of citations (each citation is a non-negative integer) of a researcher, write a function to compute the researcher’s h-index.
According to the definition of h-index on Wikipedia: “A scientist has index h if h of his/her N papers have at least h citations each, and the other N − h papers have no more than h citations each.”
image.png

"""
方法1:时间复杂度O(nlogn)+O(n) = O(nlogn)
方法2:时间复杂度O(n),因为其用了hashmap
"""
class Solution(object):
    def hIndex(self, citations):
        """
        :type citations: List[int]
        :rtype: int
        """
        # method 1:
        # citations.sort()
        # n = len(citations)
        # for i in xrange(n):
        #     if citations[i] >= (n-i): #至少有n-i个引用大于n-i
        #         return n-i
        # return 0
        
        # method 2:
        n = len(citations)
        citeCount = [0] * (n+1)
        for c in citations:
            if c >= n:
                citeCount[n] += 1
            else:
                citeCount[c] += 1

        i = n-1
        while i >= 0:
            citeCount[i] += citeCount[i+1]
            if citeCount[i+1] >= i+1:
                return i+1
            i -= 1
        return 0
题目11:179. Largest Number

Given a list of non negative integers, arrange them such that they form the largest number.
image.png

"""
此题的重点在于,如何设计sort函数的排序规则f

注:在sort函数中,cmp 指代的就是排序的规则,是一个函数,代码中lambda表达式描述的就是这个规则函数f。

def f(x,y):
    if x > y:
        return 1
    elif x < y:
        return -1
    else:
        return 0
例如:A.sort(cmp = lambda x,y: f(x,y)),会将A按升序排列。

有关sort函数,https://www.cnblogs.com/cnhkzyy/p/8678996.html
"""
class Solution(object):
    def largestNumber(self, nums):
        """
        :type nums: List[int]
        :rtype: str
        """
        
        def f(x,y): # 定义cmp函数f,默认为升序,现改成按cmp(即f)规则。
            if x+y>y+x: 
                return 1
            elif x+y<y+x:
                return -1
            else:
                return 0
        #将列表里的数字,全部转为字符串,因为需要进行字符串拼接和比较
        nums = map(str, nums)  
        
        #f(x,y)若是1,则cmp =1,则sort会交换x,y的位置;否则不交换
        nums.sort(cmp = lambda x, y: f(x,y))
        
        #再逆序,从“大”的往“小”的排
        nums = nums[::-1]
        
        #数字列表转字符串
        return '0' if nums[0] == '0' else ''.join(nums)

本次内容就到了这啦

####

更多精彩,可访问以下链接

本文章所有代码及文档均以上传至github中,感谢您的rp and star.

github链接:https://github.com/LSayhi
仓库链接:https://github.com/LSayhi/Algorithms

CSDN链接:https://blog.csdn.net/LSayhi

微信公众号:AI有点可ai

AI有点可ai.jpg

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值