力扣打卡7.13~8.04

2020 07/13

p1. 给定两个数组,编写一个函数来计算它们的交集。.示例 1: 输入:nums1 = [1,2,2,1], nums2 = [2,2] 输出:[2,2] 示例 2: 输入:nums1 = [4,9,5], nums2 = [9,4,9,8,4] 输出:[4,9]

  • 本人采用了最暴力但也是最好想的懒人方法:
    遍历短列表,如果长列表中存在就删除,然后将相同的添加到公共列表。方法比较耗时,属于偷懒行为,所以看了别人的方法。

本人方法:

class Solution:
    def intersect(self, nums1: List[int], nums2: List[int]) -> List[int]:
        same = []
        maxList = nums1 if len(nums1) >= len(nums2) else nums2 
        minList = nums1 if len(nums1) < len(nums2) else nums2
        for i in minList:
            for j in maxList:
                if j == i:
                    maxList.remove(j)
                    same.append(i)
                    break
        return same

比较好的方法思路是首先遍历两个列表,统计相同元素成为字典格式,返回两个字典相同键的小值。(只是较好吧,最好利用哈希,但是感觉代码量多了些)

P2. 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。 你可以假设每种输入只会对应一个答案。但是,数组中同一个元素不能使用两遍。 示例: 给定 nums = [2, 7, 11, 15],
target = 9 因为 nums[0] + nums[1] = 2 + 7 = 9 所以返回 [0, 1]

我的思路:采用首尾指针遍历,需要首先进行字典化,字典存储键加位置,就算有重复的,如果重复的超过了两个那它一定不是其中一个,因为就不是单一结果了。
处理重复的就是键加上“Q”,然后对数组排序,首尾遍历,如果出现重复值相加为目标值,则肯定是目标值一半。做个判断就好了,然后去字典里取值即可。


```python
class Solution:
    def twoSum(self, nums: List[int], target: int) -> List[int]:
        dict_local = {}
        for i, val in enumerate(nums):

            if str(val) in dict_local.keys():
                dict_local[str(val) + "Q"] = i
            else:
                print("111")
                dict_local[str(val)] = i
        print(dict_local)
        end = len(nums) - 1
        start = 0
        result = []
        nums.sort()
        while start < end and nums:
            if nums[start] + nums[end] == target and nums[start] != 0.5 * target:
                result.append(dict_local[str(nums[start])])
                result.append(dict_local[str(nums[end])])
                break
            if nums[start] + nums[end] == target and nums[start] == 0.5 * target:
                result.append(dict_local[str(nums[start])])
                result.append(dict_local[str(nums[end]) + "Q"])
               break
            if nums[start] + nums[end] > target:
                end = end - 1
            if nums[start] + nums[end] < target:
                start = start + 1
        return result

效率还行,占用空间较多。

2020 07/14

给定一个三角形,找出自顶向下的最小路径和。每一步只能移动到下一行中相邻的结点上。 相邻的结点 在这里指的是 下标 与 上一层结点下标
相同或者等于 上一层结点下标 + 1 的两个结点。 例如,给定三角形:

[
[2],
[3,4], [6,5,7], [4,1,8,3] ] 自顶向下的最小路径和为 11(即,2 + 3 + 5 + 1 = 11)。

class Solution:
    def minimumTotal(self, triangle: List[List[int]]) -> int:
        # 状态转移函数dp[j]=min(dp[j],dp[j+1]) + tri[i][j]
        start = triangle[len(triangle) -1]  # 初始dp为最下面那一行
        for list_ in reversed(triangle[0:-1]):
            length = len(list_)
            for i in range(length):
                start[i] = min(start[i], start[i+1]) + list_[i]
        return start[0]
  • 动态规划题目一般从最后一个开始,自下向上考虑,核心是找到状态转移方程
    本题在从下向上便利的时候,每次肯定需要携带最短路径的信息,这里不考虑路径,只需要路径长度,所以只需要记录每个最短的路径的长度信息,携带上去,每次遍历上一层的列表时,对下面那层每次取相邻两个最小值与当前遍历值相加,重新给初始列表的位置赋值即可。每层赋值都会少改变初始列表的值,顶层只会改变初始列表的第一个元素值,且最小的就是当前这个。

ps:昨夜想的方法是对每一个列表首先初始化成为字典,键为列表元素值,值为该元素在列表中的位置,对于相同的元素,键加个区别符,最后将这些字典添加到一个列表中,再将之前的列表的每一个列表进行排序。最后遍历排序后的列表的时候,每次取第一个,判断第一个元素是不是上一个元素的相邻的,如果不是,就取下一个。。。然后发现逻辑出错。记录一下错误思想。
培养动态规划题目的敏感度。

2020 7/15

给定一个整数 n,求以 1 … n 为节点组成的二叉搜索树有多少种?

示例:

输入: 3 输出: 5 解释: 给定 n = 3, 一共有 5 种不同结构的二叉搜索树:

1 3 3 2 1
\ / / / \
3 2 1 1 3 2
/ / \ \ 2 1 2 3

这里需要知道一个常识:
假设n个节点组成的二叉搜索树有G(n)种,令f(i)为以i为根的二叉搜索树的个数,则G(n) = f(1) + f(2) +…+f(n)
假设以i为根节点,其左子树结点个数为(i-1)个,右子树结点个数为(n-i)个,则有f(i)=G(i-1)G(n-i)
所以:G(n)=G(0)∗G(n−1)+G(1)∗(n−2)+…+G(n−1)∗G(0)

class Solution:
    def numTrees(self, n: int) -> int:
        f = [0] * (n+1)
        f[0] = 1
        f[1] = 1
        for i in range(2, n+1):
            for j in range(1, i+1):
                f[i] += f[j-1] * f[i-j]
        return f[n]

2020 7/16

给定一个无向图graph,当这个图为二分图时返回true。
如果我们能将一个图的节点集合分割成两个独立的子集A和B,并使图中的每一条边的两个节点一个来自A集合,一个来自B集合,我们就将这个图称为二分图。
graph将会以邻接表方式给出,graph[i]表示图中与节点i相连的所有节点。每个节点都是一个在0到graph.length-1之间的整数。这图中没有自环和平行边:
graph[i] 中不存在i,并且graph[i]中没有重复的值。 示例 1: 输入: [[1,3], [0,2], [1,3],
[0,2]] 输出: true 解释: 无向图如下: 0----1 | | | | 3----2 我们可以将节点分成两组:
{0, 2} 和 {1, 3}。 示例 2: 输入: [[1,2,3], [0,2], [0,1,3], [0,2]] 输出: false
解释: 无向图如下: 0----1 | \ | | \ | 3----2 我们不能将节点分割成两个独立的子集。 注意: graph
的长度范围为 [1, 100]。 graph[i] 中的元素的范围为 [0, graph.length - 1]。 graph[i]
不会包含 i 或者有重复的值。 图是无向的: 如果j 在 graph[i]里边, 那么 i 也会在 graph[j]里边。

  • 这道题,冥思苦想了很久,想用递归去处理,于是就踏上了不归路,想了各种特别情况,最后还是不通过,忍不了了,看答案去了,耗了得有4个小时。

想用的递归方法(未通过)

class Solution:
    def isBipartite(self, graph) -> bool:
        # 无向图G为二分图的充分必要条件是,G至少有两个顶点,且其所有回路的长度均为偶数。
        if len(graph) < 2:
            return False
        else:
            length = len(graph)
            # 开始判断每个回路长度是否是偶数
            for i in range(length):
                print(111)
                count = 0  # 回路长度
                start_list = graph[i]
                passed = []
                flag = self.IterationFunction(i, start_list, count, graph, passed)
                if not flag:  # 但凡一个不满足偶数条件直接返回false
                    return False
                else:
                    pass
            return True

    def IterationFunction(self, i, list1, count, graph, passed):
        Flag = True
        for j in list1:
            if j in passed:
                continue
            else:
                count = count + 1
                if i in graph[j]:
                    if count == 1:
                        graph[j].remove(i)
                        if graph[j]:
                            passed.append(j)
                            count = count + 1
                            return self.IterationFunction(i, graph[j], count, graph, passed)
                        else:
                            list1.remove(j)
                            count -= 1
                            if list1:
                                return self.IterationFunction(i, list1, count, graph, passed)
                            else:
                                Flag = True
                                break
                    elif count % 2 == 0:
                        # if not list1:  # 传过来的起始空了
                        #     Flag = True
                        #     break
                        # else:
                        continue

                    elif count % 2 == 1:  # 有不满足的了
                        Flag = False
                        break
                elif i not in graph[j]:
                    passed.append(j)
                    return self.IterationFunction(i, graph[j], count, graph, passed)
        return Flag


x = Solution()
print(x.isBipartite([[],[2],[1],[],[],[7,8],[7,8,9],[5,6],[5,6],[6],[12,13,14],[12],[10,11],[10],[10],[18],[17,18],[16],[15,16],[],[22,23,24],[22,23,24],[20,21],[20,21],[20,21],[27,28,29],[27,28,29],[25,26],[25,26],[25,26],[32,33,34],[33],[30],[30,31],[30],[37,39],[38],[35],[36],[35],[44],[43,44],[],[41],[40,41],[47,48,49],[47,48,49],[45,46],[45,46],[45,46]]))

答案:

从一个节点开始,先进行染色标记,对图进行遍历,当前节点的相连的所有节点都标记为与当前节点不同的颜色,表示这里两个相连的节点属于不同的集合,循环遍历。

  • 当所有节点都成功染色时,那么颜色会区分开,也就是不同颜色属于不同集合,那么返回 True,说明是二分图。
  • 如果没有成功染色,也就是遍历的过程中,会出现节点已经被染色,并且节点颜色与此时要染色的颜色不同,说明出现冲突,直接返回
    False,说明不是二分图。
# 深度优先搜索
class Solution:
    def isBipartite(self, graph: List[List[int]]) -> bool:
        def dfs(graph, node, color, signed):
            # 先判断,该节点是否被标记染色,如果被染色,判断这个节点颜色与当前要标记的颜色是否相同
            if signed[node] != 0:
                return signed[node] == color

            # 对当前节点染色,然后对相邻的节点标记不同的颜色
            signed[node] = color
            for x in graph[node]:
                if not dfs(graph, x, -color, signed):
                    return False
            return True

        length = len(graph)
        # 在这里,0:表示未标记,1、 -1:表示不同的两个颜色
        signed = [0] * length
        # 这里需要注意,有可能会存在顶点未被访问的情况,
        # 那么以这个顶点进行再一次访问
        for i in range(length):
            if (signed[i] == 0 and not dfs(graph, i, 1, signed)):
                return False

        return True



# 广度优先搜索
class Solution:
    def isBipartite(self, graph: List[List[int]]) -> bool:
        from collections import deque
        # 创建队列
        queue = deque()

        length = len(graph)
        # 在这里,0:表示未标记,1、 -1:表示不同的两个颜色
        # 标记是否被染色
        signed = [0] * length
        # 可能出现节点未被标记,存在则从它开始进行下一轮的 bfs
        for i in range(length):
            if signed[i] != 0:
                continue

            queue.append(i)
            signed[i] = 1

            # 当一个节点出队后,要将相邻的节点进行标记不同颜色并入队
            while queue:
                node = queue.popleft()
                for x in graph[node]:
                    # 如果当前节点的相邻节点已经被染色,且两者颜色相同,返回 False,表示无法成功染色
                    if signed[x] == signed[node]:
                        return False
                    # 如果未标记,进行染色,与当前节点颜色不同,并入队
                    if signed[x] == 0:
                        signed[x] = -signed[node]
                        queue.append(x)
        
        return True

2020 07/17

p1.

从上到下打印出二叉树的每个节点,同一层的节点按照从左到右的顺序打印。 例如: 给定二叉树: [3,9,20,null,null,15,7],
3
/
9 20
/
15 7
返回:
[3,9,20,15,7]
.

思路:考察二叉树的广度遍历,给定节点类,从根节点添加到循环列表中,如果左存在,则将左节点的值添加到结果列表,同时将左节点添加到循环列表中等待下次遍历,如右边一样。

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    def levelOrder(self, root: TreeNode) -> List[int]:
        if root == None:
            return []
        else:
            result = []
            temp = []
            temp.append(root)
            result.append(root.val)
            while temp:
                current = temp.pop(0)
                if current.left:
                    temp.append(current.left)
                    result.append(current.left.val)
                if current.right:
                    temp.append(current.right)
                    result.append(current.right.val)
            return result

如果是深度遍历需要分前中后,遇到再说吧,递归可解决。

p2

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

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

示例 1:

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

比较简单。。。

class Solution:
    def searchInsert(self, nums: List[int], target: int) -> int:
        if target in nums:
            return nums.index(target) 
        else:
            if target<nums[0]:
                return 0
            elif target>nums[len(nums)-1]:
                return len(nums)

            else:
                for i in range(len(nums)):
                    if nums[i] < target and nums[i+1] > target:
                        return i+1
                        

2020 07/20

p1. 给定一个已按照升序排列 的有序数组,找到两个数使得它们相加之和等于目标数。 函数应该返回这两个下标值 index1 和
index2,其中 index1 必须小于 index2。 说明: 返回的下标值(index1 和 index2)不是从零开始的。
你可以假设每个输入只对应唯一的答案,而且你不可以重复使用相同的元素。 示例: 输入: numbers = [2, 7, 11, 15],
target = 9 输出: [1,2] 解释: 2 与 7 之和等于目标数 9 。因此 index1 = 1, index2 = 2 。

比较简单,直接首位指针遍历即可,不解释。
只遍历一趟列表,时间复杂度O(n)

class Solution:
    def twoSum(self, numbers: List[int], target: int) -> List[int]:
        start = 0
        end = len(numbers) - 1
        while start < end:
            if numbers[start] + numbers[end] < target:
                start += 1
            if numbers[start] + numbers[end] > target:
                end -= 1
            if numbers[start] + numbers[end] == target:
                return [start+1,end+1]

p2.给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。
如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。 您可以假设除了数字 0 之外,这两个数都不会以 0 开头。 示例:
输入:(2 -> 4 -> 3) + (5 -> 6 -> 4) 输出:7 -> 0 -> 8 原因:342 + 465 = 807

分析可知,题目有两个需要注意的地方,两个链表长度不一样怎么办?每一位发生溢出怎么办?
考虑好这两个问题,问题就迎刃而解。可以设立一个第三个链表,并记录该链表的头(save)
其他两个链表按位相加,溢出则保留1给下一位计算,头链表不存内容,本次相加的和考虑溢出后留给第三个链表初始化next使用。

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

        save = result = ListNode(None)
        rest = 0   # 进一位?
        while l1 or l2 or rest:
            rest += (l1.val if l1 else 0) + (l2.val if l2 else 0)
            result.next = ListNode(rest % 10)
            rest = rest // 10
            result = result.next 
            l1 = l1.next if l1 else None
            l2 = l2.next if l2 else None
        return save.next

2020 07/23

p1. 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。例如,数组
[3,4,5,1,2] 为 [1,2,3,4,5] 的一个旋转,该数组的最小值为1。 示例 1: 输入:[3,4,5,1,2] 输出:1
示例 2: 输入:[2,2,2,0,1] 输出:0

题目不难,但是像采用首尾遍历的,需要多考虑一些极端情况,比如,元素只有一个,元素相等等很多情况,遇到就记下来吧。

class Solution:
    def minArray(self, numbers: List[int]) -> int:
        s = 0
        e = len(numbers) - 1
        # 采用首位指针切记考虑几种特殊情况,数组长度为1  是切记,还有就是所有元素相等情况
        if len(numbers) == 1:
            return numbers[0]
        while numbers[s]>=numbers[e] and s<e:
            s += 1
        return numbers[s]

p2. 给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。 示例 1: 输入: “abcabcbb” 输出: 3 解释:
因为无重复字符的最长子串是 “abc”,所以其长度为 3。 示例 2: 输入: “bbbbb” 输出: 1 解释:
因为无重复字符的最长子串是 “b”,所以其长度为 1。 示例 3: 输入: “pwwkew” 输出: 3 解释: 因为无重复字符的最长子串是
“wke”,所以其长度为 3。
请注意,你的答案必须是 子串 的长度,“pwke” 是一个子序列,不是子串。

最好想的应该就是诸葛遍历,然后再去遍历剩下的最后取长度做对比了,效率肯定很低。

class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        # 最好想的就是暴力求解,直接遍历,虽然时间复杂度肯定会非常高。。

        length_max = 0
        for i in range(len(s)):
            count = 0
            list_sub = []
            list_sub.append(s[i])
            for j in s[i+1:]:
                if j not in list_sub:
                    list_sub.append(j)
                    count += 1
                else:
                    if len(list_sub)>length_max:
                        length_max = len(list_sub)
                    break
            if len(list_sub)>length_max:
                length_max = len(list_sub)
        return length_max

我当然不可能只用这个方法去做,改进版本,每次记录相同元素的位置,下次遍历直接从这个位置的下一个开始遍历就好了,两个相同的元素之间不需要遍历。

class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        # 最好想的就是暴力求解,直接遍历,虽然时间复杂度肯定会非常高。。
        if len(s) == 1:
            return 1

        if len(s) > 1:
            length_max = 0
            i = 0
            while i <len(s)-1:
                list_sub = []
                list_sub.append(s[i])
                for j in range(i+1,len(s)):
                    if s[j] not in list_sub:
                        list_sub.append(s[j])
                    else:
                        index = list_sub.index(s[j])
                        i += index + 1  # 下一次循环的起点,因为两个相等的量的中间的部分不需要在遍历了
                        if len(list_sub) > length_max:
                            length_max = len(list_sub)
                        break
                if j == len(s) - 1:
                    if len(list_sub) > length_max:
                        length_max = len(list_sub)
                    break
            return length_max
        else:
            return 0

我怀疑数据量太少了,按照道理上来说,效率会提升一些,然而并没有。

瞄了一眼答案看到滑动窗口四个字,立马想到,回去修改了下代码:效率击败百分之80多

class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        if len(s) > 1:
            win = []  # 滑动窗口、
            count_max = 0
            for i in s:
                if i not in win:
                    win.append(i)
                else:
                    index = win.index(i)
                    if len(win) > count_max:
                        count_max = len(win)
                    win = win[index+1:] if len(win) != 1 else []
                    win.append(i)
            if count_max<len(win):
                count_max = len(win)
            return count_max
        elif len(s)<=1:
            return len(s)

2020 07/24

p1. 给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。
说明:每次只能向下或者向右移动一步。 示例: 输入: [ [1,3,1], [1,5,1], [4,2,1] ] 输出: 7
解释: 因为路径 1→3→1→1→1 的总和最小。

见识了记忆搜索法:每次走位的时候记录走到这个位置的最短路径,也就反馈在修改这个位置对应的值上。

class Solution:
    def minPathSum(self, grid: List[List[int]]) -> int:
        # 可采用记忆搜索法,及每个位置都记录了到这个位置的最短路径
        for i in range(len(grid)):  # 遍历所有行
            for j in range(len(grid[0])):  #遍历所有列
                if i == j ==0:   # 左上角元素
                    continue
                elif i == 0:  # 当横向走位
                    grid[i][j] = grid[i][j-1] + grid[i][j]
                elif j == 0: # 纵向走位
                    grid[i][j] = grid[i-1][j] + grid[i][j]
                else:
                    grid[i][j] = min(grid[i-1][j],grid[i][j-1]) + grid[i][j]
        return grid[-1][-1]

p2. 将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 示例: 输入:1->2->4,
1->3->4 输出:1->1->2->3->4->4

有序列表的拼接,主要考虑长度不一致,一方遍历可能会先结束如何处理,还有就是设定头节点和保存头结点。

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode:
        # 链表题 注意点就是创建表头,并且要记录下表头,因为你最后可能需要返回
        head = ListNode(None)
        cur = head
        while l1 and l2:
            if l1.val < l2.val:
                cur.next = l1
                l1 = l1.next
            else:
                cur.next = l2
                l2 = l2.next
            cur = cur.next

        if l1:   #遍历某一条链表结束了,剩下的直接品过去
            cur.next = l1
        else:
            cur.next=l2
        return head.next

2020 7/28

给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。 示例 1: 输入: “babad” 输出:
“bab” 注意: “aba” 也是一个有效答案。 示例 2: 输入: “cbbd” 输出: “bb”

解题思想:我这里采用找中心轴的方法,每次以当前遍历的值为中心点,散开往两头找,去做比较。主要是需要考虑较多特殊情况:
1、出现奇数个相同的值
2、出现偶数个相同值
3、只有一个字符的时候
4、初始值最长回文不能用len()求长度
5、往两头找找到尽头了

总结:题目不难 情况要考虑全面。

class Solution:
    def longestPalindrome(self, s: str) -> str:
        # 如果只有一个字符
        if len(s) == 1:
            return s

        max_str = "" 
        for i in range(0,len(s)-1):
            # 如果遇到连续俩是一样的 这里还要再分可能出现奇数个相同的,两种遍历比较大小吧
            if s[i] == s[i+1]:
                max_str = self.find(i,i+1,s,"",max_str) if len(self.find(i,i+1,s,"",max_str))                   > len(self.find(i-1,i+1,s,s[i],max_str)) else self.find(i-1,i+1,s,s[i],                         max_str)
            # 如果连续俩不一样,那每个都可以作为中心轴
            else:
                max_str = self.find(i - 1,i + 1,s,s[i],max_str)
        return max_str

    def find(self, head, tail, s, str1, max_str):
            while head>=0 and tail <=len(s) - 1:
                if  s[head] == s[tail]:
                    str1 = s[head] + str1 + s[tail]
                    head -= 1
                    tail += 1 
                else:
                   break
            if max_str:
                if len(max_str) < len(str1):
                    max_str = str1
                    return max_str
            else:
                max_str = str1
            return max_str

2020 7/29

给定一个正整数 n,将其拆分为至少两个正整数的和,并使这些整数的乘积最大化。 返回你可以获得的最大乘积。 示例 1: 输入: 2 输出: 1
解释: 2 = 1 + 1, 1 × 1 = 1。 示例 2: 输入: 10 输出: 36 解释: 10 = 3 + 3 + 4, 3 ×
3 × 4 = 36。 说明: 你可以假设 n 不小于 2 且不大于 58。

它的数学证明很有趣,可以看下,显示均值不等式证明给定数量的划分时,均分值最大,然后再用求导证明尽量取3时最大。

class Solution:
    def integerBreak(self, n: int) -> int:
        # 尽可能用3去分,考虑余数012三种
        if n <= 3:
            return n-1
        else:
            rest = n % 3    # 余数
            count = n // 3
            if rest == 0:
                return pow(3,count)
            if rest == 1:
                return pow(3,count-1) * 4
            if rest == 2:
                return pow(3,count) * 2

2020 7/30

将一个给定字符串根据给定的行数,以从上往下、从左到右进行 Z 字形排列。 比如输入字符串为 “LEETCODEISHIRING” 行数为 3
时,排列如下: L C I R E T O E S I I G E D H N
之后,你的输出需要从左往右逐行读取,产生出一个新的字符串,比如:“LCIRETOESIIGEDHN”。

请你实现这个将字符串进行指定行数变换的函数: string convert(string s, int numRows); 示例 1:
输入: s = “LEETCODEISHIRING”, numRows = 3 输出: “LCIRETOESIIGEDHN” 示例 2:
输入: s = “LEETCODEISHIRING”, numRows = 4 输出: “LDREOEIIECIHNTSG” 解释: L
D R E O E I I E C I H N T S G

找规律题。 一定要记住考虑 字符串相关问题 的字符串长度 或者什么参数为0,1 的情况。

class Solution(object):
    def convert(self, s, numRows):
        if numRows == 1:
            return s
        result = ""
        # 遍历每一行取数据
        length = len(s)-1
        for i in range(0,numRows):
            j = i    # 每行第一个元素
            if i<=length:
                if i !=0 and i !=numRows-1:
                    result = result + s[j]
                    j = j + 2*(numRows-i-1)
                    while j <= length:
                        result = result + s[j]
                        j = j + 2*i
                        if j<=length:
                            result = result + s[j]
                            j = j + 2*(numRows-i-1)
                elif i == 0 or i == numRows-1:
                     while j <= length:
                        result = result + s[j]
                        j = j + 2*(numRows-1)
                    
        return result

2020 08/03
p1.

给出一个 32 位的有符号整数,你需要将这个整数中每位上的数字进行反转。 示例 1: 输入: 123 输出: 321 示例 2: 输入:
-123 输出: -321 示例 3: 输入: 120 输出: 21 注意: 假设我们的环境只能存储得下 32 位的有符号整数,则其数值范围为 [−231, 231 − 1]。请根据这个假设,如果反转后整数溢出那么就返回 0。

比较简单,思想就是转为字符再转回来。

class Solution(object):
    def reverse(self, x):
        """
        :type x: int
        :rtype: int
        """
        if x == 0:
            return 0
        if x > 0:
            str1 = self.reverse1(x)
            return 0 if str1 > pow(2,31)-1 else str1
        if x < 0:
           str1 = str(x)[1:]
           str1 = self.reverse1(str1)
           return 0 if str1 > pow(2,31) else 0-str1

    def reverse1(self,x):
        str1 = str(x)
        i = len(str1) - 1
        while str1[i] == '0':
            i -= 1
        str1 = str1[:i+1]
        str1 = str1[::-1]
        str1 = int(str1)
        return str1

p2.

请你来实现一个 atoi 函数,使其能将字符串转换成整数。
首先,该函数会根据需要丢弃无用的开头空格字符,直到寻找到第一个非空格的字符为止。接下来的转化规则如下:
如果第一个非空字符为正或者负号时,则将该符号与之后面尽可能多的连续数字字符组合起来,形成一个有符号整数。
假如第一个非空字符是数字,则直接将其与之后连续的数字字符组合起来,形成一个整数。
该字符串在有效的整数部分之后也可能会存在多余的字符,那么这些字符可以被忽略,它们对函数不应该造成影响。
注意:假如该字符串中的第一个非空格字符不是一个有效整数字符、字符串为空或字符串仅包含空白字符时,则你的函数不需要进行转换,即无法进行有效转换。
在任何情况下,若函数不能进行有效的转换时,请返回 0 。 提示: 本题中的空白字符只包括空格字符 ’ ’ 。 假设我们的环境只能存储 32
位大小的有符号整数,那么其数值范围为 [−231, 231 − 1]。如果数值超过这个范围,请返回 INT_MAX (231 − 1)
或 INT_MIN (−231) 。 示例 1: 输入: “42” 输出: 42 示例 2: 输入: " -42" 输出: -42
解释: 第一个非空白字符为 ‘-’, 它是一个负号。
我们尽可能将负号与后面所有连续出现的数字组合起来,最后得到 -42 。 示例 3: 输入: “4193 with words” 输出: 4193 解释: 转换截止于数字 ‘3’ ,因为它的下一个字符不为数字。 示例 4: 输入: “words and 987” 输出:
0 解释: 第一个非空字符是 ‘w’, 但它不是数字或正、负号。
因此无法执行有效的转换。 示例 5: 输入: “-91283472332” 输出: -2147483648 解释: 数字 “-91283472332” 超过 32 位有符号整数范围。
因此返回 INT_MIN (−231) 。

感觉不想动脑子,干脆把几种情况都写出来好了,其实就是一行正则的事情。

class Solution(object):
    def myAtoi(self, str):
        """
        :type str: str
        :rtype: int
        """
        data = ["0","1","2","3","4","5","6","7","8","9"]
        # 去掉开头结尾的空格
        str = str.strip()
        # 如果去除空格后字符串的长度仍然不为0
        if len(str) >= 2:
            i = 0
            # 开头是个负号
            if str[0] == "-":
                i += 1
                while i < len(str):
                    # 说明是数字0-9
                    if str[i] in data: 
                        i += 1
                    else:
                        break
                if i == 1:  # 说明只有个负号是有效字符,直接返回0
                    return 0
                else:
                    str = str[1:i]
                    str = int(str)
                    if str > pow(2,31):
                        return 0-pow(2,31)
                    else:
                        return 0-str
             # +号开头
            elif str[0] == '+':
                str = str[1:]

                while i < len(str):
                    if str[i] in data: 
                        i += 1
                    else:
                        break
                if i == 0:
                    return 0
                else:
                    str = int(str[0:i])
                    if str > pow(2,31) - 1:
                        return pow(2,31) -1
                    else:
                        return str
            # 开头是数字
            elif str[0] in data:
                while i < len(str):
                    if str[i] in data: 
                        i += 1
                    else:
                        break
                  
                str = str[0:i]
                str = int(str)
                if str > pow(2,31) - 1:
                    return pow(2,31) -1
                else:
                    return str
            # 压根开头就不是数字
            elif str[0] not in data:
                return 0
           
        # 说明去出空格后只有0或者l个字符
        else:
            if len(str) == 1:
                if str[0] in data:
                    return int(str[0])
                else:
                    return 0
            else:
                return 0
        
              

2020 08/04

判断一个整数是否是回文数。回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。

示例 1:

输入: 121 输出: true 示例 2:

输入: -121 输出: false 解释: 从左向右读, 为 -121 。 从右向左读, 为 121- 。因此它不是一个回文数。 示例
3:

输入: 10 输出: false 解释: 从右向左读, 为 01 。因此它不是一个回文数。 进阶: 你能不将整数转为字符串来解决这个问题吗?

一开始没注意到不要转为字符串解决。先贴上字符串解决的方法。

class Solution(object):
    def isPalindrome(self, x):
        """
        :type x: int
        :rtype: bool
        """
        if x < 0:
            return False
        elif x == 0:
            return True
        elif x > 0:
            str1 = str(x)
            str2 = str1[::-1]
            if str1 == str2:
                return True
            else:
                return False

如果不用字符串解决来判断的话,需要先思考集中可能性,负数和个位为零的肯定不是,所以直接return False,对于剩下的数,可以考虑折半比较法,如果是偶数个数,则如果是回文数一定会出现,每次不停的%10后的数相加再乘以10叠加的过程会出现和剩下的x相等的情况,奇数位数的则会出现,x和每次不停%10后的数相加后再乘以10的数除以10后的值相等。

class Solution:
    def isPalindrome(self, x: int) -> bool:
        if x < 0 or (x % 10 == 0 and x != 0):
            return False
        revertedNumber = 0
        while x > revertedNumber:
            revertedNumber = revertedNumber * 10 + x % 10
            x //= 10
        return x == revertedNumber or x == revertedNumber // 10
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值