楔子
先说结论,个人觉得拷贝、粘贴Excel内容指令更好用,支持跨行拷贝Excel数据。
大家好,我是张桃狮。
我每天都会用影刀查询订单物流单号,并写入订单台账。
写完以后,我的习惯是将已发出的订单和未发出的订单分组,并保持原有订单排序。
这个操作,也是用影刀来完成的。
具体操作步骤是用循环,让影刀读取每一行已发出的订单,写入到上面的空白行里面去。
如果订单比较少还算方便,可以看到有趣的动画效果。
可是如果订单达到几十个后,就有点耽误时间了。
我尝试优化这个操作。
经过观察,我发现读取、写入Excel内容指令,只对Excel表格中的连续数据区域有效。
如果是跨行的数据,就需要多次读取、写入,无法做到一次完成。
就在发愁的时候,我发现功能比较类似的拷贝、粘贴Excel内容指令支持输入用英文逗号分开的多个行号。
这就好办了,我只需要将需要复制粘贴上去的行,一次性复制粘贴上去就行了。
具体步骤如下。
先将未排序的物流单号非空的行号写入列表,获取列表长度。
在第一个物流单号为空的行上面插入列表长度的空行。
将列表中的行号都加上列表长度,并将行号按照格式填写到拷贝Excel内容指令中。
粘贴Excel内容,并将原行删除。
闲话讲完,咱们继续力扣刷题。
力扣234. 回文链表
给你一个单链表的头节点 head ,请你判断该链表是否为回文链表。如果是,返回 true ;否则,返回 false 。
示例 1:

输入:head = [1,2,2,1]
输出:true
示例 2:

输入:head = [1,2]
输出:false
提示:
链表中节点数目在范围[1, 105] 内
0 <= Node.val <= 9
进阶:你能否用 O(n) 时间复杂度和 O(1) 空间复杂度解决此题?
我的思路
先将链表的值遍历为列表,判断列表是否与列表[::-1]相等。
# Definition for singly-linked list.# class ListNode:# def __init__(self, val=0, next=None):# self.val = val# self.next = nextclass Solution: def isPalindrome(self, head: Optional[ListNode]) -> bool: ls=list() current=head while current: ls.append(current.val) current=current.next return ls==ls[::-1]
力扣提交通过,时间复杂度O(n),空间复杂度O(n)。
空间复杂度不符合题目进阶要求,我打算先看看官方题解。
力扣官方题解
方法一:将值复制到数组中后用双指针法
class Solution: def isPalindrome(self, head: ListNode) -> bool: vals = [] current_node = head while current_node is not None: vals.append(current_node.val) current_node = current_node.next return vals == vals[::-1]
力扣提交通过,时间复杂度O(n),空间复杂度O(n)。
思路跟我的代码基本一样。
方法二:递归
class Solution: def isPalindrome(self, head: ListNode) -> bool: self.front_pointer = head def recursively_check(current_node=head): if current_node is not None: if not recursively_check(current_node.next): return False if self.front_pointer.val != current_node.val: return False self.front_pointer = self.front_pointer.next return True return recursively_check()
力扣提交通过,时间复杂度O(n),空间复杂度O(n)。
这个递归代码我写不出来,看勉强能看懂。
代码里的递归函数recursively_check会遍历链表到尾部,再开始回归。
相当于链表头和链表尾各有一个指针相向而行,每走一步都会比对两个节点的值是否相等。
因为递归需要用到栈帧,所以空间复杂度还是O(n),并没有满足题目要求。
方法三:快慢指针
class Solution: def isPalindrome(self, head: ListNode) -> bool: if head is None: return True # 找到前半部分链表的尾节点并反转后半部分链表 first_half_end = self.end_of_first_half(head) second_half_start = self.reverse_list(first_half_end.next) # 判断是否回文 result = True first_position = head second_position = second_half_start while result and second_position is not None: if first_position.val != second_position.val: result = False first_position = first_position.next second_position = second_position.next # 还原链表并返回结果 first_half_end.next = self.reverse_list(second_half_start) return result def end_of_first_half(self, head): fast = head slow = head while fast.next is not None and fast.next.next is not None: fast = fast.next.next slow = slow.next return slow def reverse_list(self, head): previous = None current = head while current is not None: next_node = current.next current.next = previous previous = current current = next_node return previous
力扣提交通过,时间复杂度O(n),空间复杂度O(1)。
做链表题想要把空间复杂度降到O(1),看来只能玩指针了。
代码中出现三个函数,每个都是通过指针完成。
end_of_first_half函数通过快慢指针找到链表中部。
慢指针每次走1步,快指针每次走2步。
快指针走完全程,慢指针的位置就是链表中部节点。
reverse_list函数将后半部分链表的指针做了反转。
python中没有指针的概念,我对指针的理解是变量在内存中的地址。
所以A=B,B=1,就相当于A=1,如果给B重新赋值为2,也不会影响A=1。
注意这里的1和2是不可变类型,包括数字、字符串、元组。
如果是可变类型(列表、字典、集合),原地修改B的内容,A也会跟着改变。
isPalindrome函数需要调用上面这两个函数。
先找到链表的中间节点,再将后面部分链表指针反转,然后在逐个比较链表值是否相同,最后将后半部分链表指针恢复回来。
这个思路我隐约想到了,但是觉得太复杂,没有勇于尝试,还是不够自信呀。
我是个编程爱好者,小白级别的,如果你跟我一样希望通过力扣刷题,学习各种奇妙的算法,可以关注我,大家一起学习。