Bytedance面试高频题

重建二叉树

1、这道题的重点在认识到先序遍历的第一个点就是根节点,并且这个点可以在中序遍历中定位到左右子树。
2、要注意到,每次构造其实就是根节点-左子树-右子树,由中序遍历的根节点可以知道根节点左边的点都在左子树的点,并且左子树有多少点就对应着先序遍历后面的点,因为先根再左。

class Solution:
    def buildTree(self, preorder: List[int], inorder: List[int]) -> TreeNode:
        if not preorder:
            return None
        
        def find(x, inorder):
            for i in range(len(inorder)):
                if inorder[i] == x:
                    return i

        def reconstruct(preorder, inorder):
            if not preorder:
                return 
            root = TreeNode(preorder[0])
            j = find(preorder[0], inorder)
            root.left = reconstruct(preorder[1:j+1], inorder[0:j])
            root.right = reconstruct(preorder[j+1:], inorder[(j+1):]) # 这个点很重要
            # 虽然可以定位到根节点,但是要明白根节点左边由多少位,其实也代表先序遍历后面有多少位,因为先根再左,左边有多少位肯定在根节点后面。
            return root
            
        return reconstruct(preorder, inorder)

优化:
不新建列表,直接通过序号,使用hashmap–注意只要有思路,肯定能写,如果比较复杂先写之后代入case验证-修改。

class Solution:
    # 返回构造的TreeNode根节点---注意只要有思路,肯定能写,如果比较复杂先写之后代入case验证-修改。
    def buildTree(self, preorder: List[int], inorder: List[int]) -> TreeNode:
        # write code here
        if not preorder:
            return None
        record = {
    
    }
        pre = preorder
        tin = inorder
        for i in range(len(inorder)):
            record[tin[i]] = i
            
        def reconstrut(pre_start, pre_end, tin_start, tin_end):
            if pre_start > pre_end or tin_start > tin_end:
                return 
            node = TreeNode(pre[pre_start])
            mid = record[pre[pre_start]]
            node.left = reconstrut(pre_start+1, pre_start + mid-tin_start,tin_start, mid-1)
            node.right = reconstrut(pre_start+ mid-tin_start+1, pre_end, mid+1, tin_end)
            return node
            
        return reconstrut(0, len(pre)-1, 0, len(tin)-1)

剑指 Offer 55 - I. 二叉树的深度

输入一棵二叉树的根节点,求该树的深度。从根节点到叶节点依次经过的节点(含根、叶节点)形成树的一条路径,最长路径的长度为树的深度。

例如:

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

3

/
9 20
/
15 7
返回它的最大深度 3 。

class Solution(object):
    def maxDepth(self, root):
        """
        :type root: TreeNode
        :rtype: int
        """
        if not root:
            return 0

        def dfs(root, n):
            if not root:
                return n - 1
            num1 = dfs(root.left, n+1)
            num2 = dfs(root.right, n+1)
            if num1 > num2:
                return num1
            else:
                return num2
        return dfs(root, 1)

平衡二叉树

都是二叉树的深度改进来的,可能做了上道题之后比较顺利
输入一棵二叉树,判断该二叉树是否是平衡二叉树。
在这里,我们只需要考虑其平衡性,不需要考虑其是不是排序二叉树
平衡二叉树(Balanced Binary Tree),具有以下性质:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。
{1,2,3,4,5,6,7} — True

class Solution:
    def dfs(self, root, n):
         if not root:
             return n - 1
         m1 = self.dfs(root.left, n+1)
         m2 = self.dfs(root.right, n+1)
         if m1 > m2:
             return m1
         else:
             return m2
    def IsBalanced_Solution(self, pRoot):
        # write code here
        if not pRoot:
            return True
        num1 = self.dfs(pRoot.left, 1)
        num2 = self.dfs(pRoot.right, 1)
        if abs(num1 - num2) > 1:
            return False
        else:
            return self.IsBalanced_Solution(pRoot.left) and self.IsBalanced_Solution(pRoot.right)
            

把数字翻译成字符串

https://blog.csdn.net/caihuanqia/article/details/105899790

88. 合并两个有序数组–坑很大

给你两个有序整数数组 nums1 和 nums2,请你将 nums2 合并到 nums1 中,使 nums1 成为一个有序数组。
初始化 nums1 和 nums2 的元素数量分别为 m 和 n 。你可以假设 nums1 有足够的空间(空间大小等于 m + n)来保存 nums2 中的元素。

示例 1:
输入:nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3
输出:[1,2,2,3,5,6]
示例 2:
输入:nums1 = [1], m = 1, nums2 = [], n = 0
输出:[1]

这题其实很简单,但是坑很大。
1、首先,因为题目读取的nums1的地址,像这种赋值类的题目,题目是不会听从你的变量名的,就算是不return也是照样可以运行。所以,必须实际修改num1初始地址对应的列表。
nums1.clear()可以原地清除列表内的元素–python3才有,或者nums1[:] = []
不可以 nums1 = [],因为只是对于nums1更换了一个地址,重新初始化了,并没有针对原地址进行。
2、nums1 += nums2[1:2] 注意,这样还在nums1的地址上进行更改
但是,如果是nums1 = nums1 + nums2[1:2]—重新开辟了地址,源地址还是没有得到更改。

import copy
class Solution(object):
    def merge(self, nums1, m, nums2, n):

        start_1 = 0
        start_2 = 0
        nums1_copy = copy.deepcopy(nums1) # / nums1_copy = nums[0:m] --浅拷贝了--只是拷贝了第一层--一维的数组有效
        nums1.clear()  # 这道题之所以重新初始化无效,是因为题目记住了nums1原来的id,就是地址,所以重新初始化得到了其他的新地址。这道题就算是不return也是可以的。
        while start_1 < m and start_2 < n:
            if nums1_copy[start_1] <= nums2[start_2]:
                nums1.append(nums1_copy[start_1])
                start_1 += 1
            else:
                nums1.append(nums2[start_2])
                start_2 += 1
        if start_1 == m:
            nums1 += nums2[start_2:]   ###切记不可以 nums1 = nums1 + nums2[start_2:]--地址改变
        else:
            nums1 += nums1_copy[start_1:m]
        return nums1    

nums2 = nums1[0:3]–这个浅拷贝也只是针对了一维数组

nums1 = [[1,2,3,4],[1,2,3,4],[1,2,3,4]]
print(id(nums1))
nums2 = nums1[0:3] # ==  nums2 = num1.copy()
print(id(nums2))
nums2[0][1] = 10
print(nums2)
print(nums1)
[[1, 10, 3, 4], [1, 2, 3, 4], [1, 2, 3, 4]]
[[1, 10, 3, 4], [1, 2, 3, 4], [1, 2, 3, 4]]

所以下次面对赋值类的题目还有列表的拷贝题目,直接用上copy.deepcopy避免出现想不到的问题。赋值类的题目要切记地址是否改变了,如果地址改变了,那么改变就是无效的

反转链表

题目描述
输入一个链表,反转链表后,输出新链表的表头。
输入
{1,2,3}
返回值
{3,2,1}

头插法建表

class Solution:
    # 返回ListNode
    def ReverseList(self, pHead):
        # write code here
        if not pHead:
            return pHead
        head1 = pHead
        head2 = pHead.next
        if not head2:
            return head1
        
        head3 = pHead.next.next
        head1.next = None
        head2.next = head1
        head1 = head2
        head2 = head3
        while head2:
            head3 = head2.next
            head2.next = head1
            head1 = head2
            head2 = head3
        return head1

LRU

哈希表查找快,但是数据无固定顺序;链表有顺序之分,插入删除快,但是查找慢。所以结合一下,形成一种新的数据结构:哈希链表 LinkedHashMap。在这里插入图片描述
使用双向链表的原因:因为我们需要删除操作。删除一个节点不光要得到该节点本身的指针,也需要操作其前驱节点的指针,而双向链表才能支持直接查找前驱,保证操作的时间复杂度 O(1)。

146. LRU 缓存机制

运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制 。
实现 LRUCache 类:

LRUCache(int capacity) 以正整数作为容量 capacity 初始化 LRU 缓存
int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1 。
void put(int key, int value) 如果关键字已经存在,则变更其数据值;如果关键字不存在,则插入该组「关键字-值」。当缓存容量达到上限时,它应该在写入新数据之前删除最久未使用的数据值,从而为新的数据值留出空间。

进阶:你是否可以在 O(1) 时间复杂度内完成这两种操作?
示例:

输入
[“LRUCache”, “put”, “put”, “get”, “put”, “get”, “put”, “get”, “get”, “get”]
[[2], [1, 1], [2, 2], [1], [3, 3], [2], [4, 4], [1], [3], [4]]
输出
[null, null, null, 1, null, -1, null, -1, 3, 4]
解释
LRUCache lRUCache = new LRUCache(2);
lRUCache.put(1, 1); // 缓存是 {1=1}
lRUCache.put(2, 2); // 缓存是 {1=1, 2=2}
lRUCache.get(1); // 返回 1
lRUCache.put(3, 3); // 该操作会使得关键字 2 作废,缓存是 {1=1, 3=3}
lRUCache.get(2); // 返回 -1 (未找到)
lRUCache.put(4, 4); // 该操作会使得关键字 1 作废,缓存是 {4=4, 3=3}
lRUCache.get(1); // 返回 -1 (未找到)
lRUCache.get(3); // 返回 3
lRUCache.get(4); // 返回 4

思路:做法还是比较直接,输入:通过双向链表每次存储新put进来的key,如果已经存在,把原来双向链表中的节点移到链表的尾部—通过字典存储对应的key和node每次进新的key就找对应的node—O(1);不存在的话就每次新添加都是在尾部进行添加。输出:每次也是直接在字典中找对应的key,不存在返回-1,存在的话则把对应的value返回,并且节点移到尾部。—需要注意的是新的操作之后,如果是替换或者是输出,都必须把已存在的节点移动到链表的尾部—所以需要熟练链表的操作。并且双链表的头节点和尾节点都设置为空,便于运算。


class Linklist(object):
    def __init__(self, x=None):
        self.val = x
        self.next = None
        self.last = None
### 难怪一直出错,双向链表为了避免麻烦,首尾都放了一个空节点
### .next / .last具体已经指向哪个节点需要非常明确,不然就是浪费一堆时间出不来结果,最好用笔画好。
class LRUCache(object):
    def __init__(self, capacity):
        self.capacity = capacity
        self.record = {
    
    }
        self.result = []
        self.head1 = Linklist() ## 头节点和尾节点是空的
        self.last1 = Linklist()
        self.last1.last = self.head1
        self.head1.next = self.last1


    def move_to_end(self, key, node, value):
        node.last.next = node.next
        node.next.last = node.last
        node = Linklist(key)
        self.last1.last.next = node
        node.last = self.last1.last
        self.last1.last = node
        node.next = self.last1
        self.record[key] = (node, value)

    def add_to_end(self, key, node, value):
        self.last1.last.next = node
        node.last = self.last1.last
        self.last1.last = node
        node.next = self.last1
        self.record[key] = (node, value)
        if len(self.record) > self.capacity:
            node = self.head1.next
            del self.record[node.val]
            # node.last.next = node.next
            # node.next.last = node.last
            self.head1.next = self.head1.next.next
            self.head1.next.last = self.head1


    def get(self, key):
        if key not in self.record:
            return -1
        else:
            node, val = self.record[key]
            self.move_to_end(key, node, val)
            return val


    def put(self, key, value):

        if key not in self.record:
            node = Linklist(key)
            self.add_to_end(key, node, value)
        else:
            node, val = self.record[key]
            self.move_to_end(key, node, value)

牛客
设计LRU缓存结构,该结构在构造时确定大小,假设大小为K,并有如下两个功能
set(key, value):将记录(key, value)插入该结构
get(key):返回key对应的value值
set和get方法的时间复杂度为O(1)
某个key的set或get操作一旦发生,认为这个key的记录成了最常使用的。
当缓存的大小超过K时,移除最不经常使用的记录,即set或get最久远的。
若opt=1,接下来两个整数x, y,表示set(x, y)
若opt=2,接下来一个整数x,表示get(x),若x未出现过或已被移除,则返回-1
对于每个操作2,输出一个答案
牛客 链表只有CPP可以通过,python只能通过OrderedDict通过。

#include <unordered_map>

struct DListNode{
    
    
    int key, val;
    DListNode* pre;
    DListNode* next;
    DListNode(int k, int v): key(k), val(v), pre(nullptr), next(nullptr){
    
    };
};


class Solution {
    
    
private:
    int size = 0;
    DListNode* head;
    DListNode* tail;
    unordered_map<int, DListNode*> mp;

public:
    /**
     * lru design
     * @param operators int整型vector<vector<>> the ops
     * @param k int整型 the k
     * @return int整型vector
     */
    vector<int> LRU(vector<vector<int> >& operators, int k) {
    
    
        // write code here
        if(k < 1) return {
    
    };
        this->size = k;
        this->head = new DListNode(0,0);
        this->tail = new DListNode(0,0);
        this->head->next = this->tail;
        this->tail->pre = this->head;

        if(operators.size() == 0) return {
    
    };

        vector<int> res;

        for(vector<int> op : operators){
    
    
            if(op[0] == 1) {
    
    
                set(op[1], op[2]);
            }
            else if(op[0] == 2){
    
    
                int value = get(op[1]);
                res.push_back(value);
            }
        }
        return res;
    }

    void set(int key, int val){
    
    
        if(mp.find(key) == mp.end()){
    
     // hashmap 中没找到
            DListNode* node = new DListNode(key, val);
            mp[key] = node;
            if(this->size <= 0){
    
    
                removeLast();
            }
            else{
    
    
                this->size--;
            }
            insertFirst(node);
        }
        else{
    
      // hashmap 中已经有了,也就是链表里也已经有了
            mp[key]->val = val;
            moveToHead(mp[key]);
        }
    }


    int get(int key){
    
    
        int ret = -1;
        if(mp.find(key) != mp.end()){
    
    
            ret = mp[key]->val;
            moveToHead(mp[key]);
        }
        return ret;
    }

    void moveToHead(DListNode* node){
    
    
        if(node->pre == this->head) return;
        node->pre->next = node->next;
        node->next->pre = node->pre;
        insertFirst(node);
    }


    void removeLast(){
    
    
        mp.erase(this->tail->pre->key);
        this->tail->pre->pre->next = this->tail; // remove the last node in dlist
        this->tail->pre = this->tail->pre->pre;
    }

    void insertFirst(DListNode* node){
    
    
        node->pre = this->head;
        node->next = this->head->next;
        this->head->next->pre = node;
        this->head->next = node;
    }

};

树的直径

合并K个排序链表–牛客还不熟,bugfree还有很大距离。

粗心主要出现在变量打错,循环出问题–for循环里删除元素,会导致没有完全遍历。改成while。

题目描述
合并\ k k 个已排序的链表并将其作为一个已排序的链表返回。分析并描述其复杂度。
示例1
输入 [{1,2,3},{4,5,6,7}]
返回值 {1,2,3,4,5,6,7}

class Solution:
    def mergeKLists(self , lists ):
        # write code here
        
        new_list = None
        n = 0
        ######################################本题的错误点粗心在这里,
        #for循环里面删除列表元素,导致跳跃,并没有遍历完全
        #for i in lists:
        #	if not i:
	    #   		lists.remove(i)
        while n < len(lists):
            if not lists[n]: 
                lists.remove(lists[n])
            else:
                n += 1
                
        if not lists:
            return None
        
        def create_list(new_list, lists):
            if not lists:
                return None
            while lists:
                miniest = 100000
                for node in lists:
                    if node.val < miniest:
                        miniest = node.val   # 变量不可粗心写错,牛客根本无法看出!!!
                        head = node
                lists.remove(head)
                new = ListNode(head.val)
                res = head.next
                head.next = None
                
                if res:
                    lists.append(res)
                if not new_list:
                    new_list = new
                    new_head = new
                else:
                    new_list.next = new
                    new_list = new
            return new_head
        return create_list(new_list, lists)

剑指 Offer 48. 最长不含重复字符的子字符串

请从字符串中找出一个最长的不包含重复字符的子字符串,计算该最长子字符串的长度。
示例 1:
输入: “abcabcbb”
输出: 3
解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。
示例 2:
输入: “bbbbb”
输出: 1
解释: 因为无重复字符的最长子串是 “b”,所以其长度为 1。

例如:abcaba
其实本题的难点在于在使用哈希来保存的时候,出现新的元素固然必须要重新计数,计数的开端是上次该元素的位置的下一个。开始是a,遇到第四个时,开始就是b,凑成bca,所以哈希表前面的元素就需要清除掉—这是单纯从哈希表存储的内容进行考虑的,所以需要一个记录存储顺序的队列/列表,每次遇到重复元素,start新之后,也要把该元素之前放进哈希的也清除掉。后续直接使用可以记录顺序的OrderedDict就可以解决这个问题----但是,关键 其实只需要明白一个关键—就是当前序号减去之前哈希存储的序号,如果大于length(也就是目前的长度),说明就不在目前的length的记录范围之内,所以可以不care.

但是最好的解题方法是动态规划 注意 dp的状态不一定要设置成要求的量,灵活!
状态定义: 设动态规划列表 dp ,dp[j] 代表以字符 s[j] 为结尾的 “最长不重复子字符串” 的长度。
状态转移方程:
dp[i] = dp[i-1] + 1 if arr[i] not in record or i - record[i] > dp[i-1]
dp[i] = i - record[i] if i - record[i] <= dp[i-1]

动态规划

class Solution:
    def lengthOfLongestSubstring(self , arr ):
        # 状态定义: 设动态规划列表 dp ,dp[j] 代表以字符 s[j] 为结尾的 “最长不重复子字符串” 的长度。--必须是包含arr[i]的,并不是arr[0:i+1]最大的。
        record = {
    
    }
        if not arr:
            return 0
        dp = [0] * len(arr)
        for i in range(len(arr)):
            if i == 0:
                record[arr[i]] = i
                dp[i] = 1
                continue
            if arr[i] not in record:
                dp[i] = dp[i-1] + 1
            else:
                if i - record[arr[i]] <= dp[i-1]:
                    dp[i] = i - record[arr[i]]
                else:
                    dp[i] = dp[i-1] + 1
            record[arr[i]] = i
            
        return max(dp)

哈希-- OrderedDict

from collections import OrderedDict
class Solution:
    def lengthOfLongestSubstring(self , arr ):
        # write code here
        # 这道题开始出现的问题在于没有意识到,如果是一个新的开始,那么其实前面进入字典的键不再生效,从上一个重复的键之前的那些键,所以这种做法是通过OrderedDict的有序性来解除这种危机。
        record = OrderedDict()
        lengths = []
        length = 0
        if not arr:
            return 0
        for i in range(len(arr)):
            if arr[i] in record:
                lengths.append(length)
                start = record[arr[i]] + 1
                popitem = record.popitem(last=False)[0]
                while  popitem != arr[i]:
                    popitem = record.popitem(last=False)[0]
                record[arr[i]] = i
                length = i - start + 1
            else:
                record[arr[i]] = i
                length += 1
        lengths.append(length)
        return max(lengths)

使用判断条件去除OrderedDict而使用字典

class Solution:
    def lengthOfLongestSubstring(self , arr ):
        # write code here
        record = {
    
    }
        lengths = []
        length = 0
        if not arr:
            return 0
        for i in range(len(arr)):
            if arr[i] in record:
            
                if i - record[arr[i]] > length:  # 加上关键的判断语句
                    record[arr[i]] = i
                    length += 1
                    continue
                
                lengths.append(length)
                start = record[arr[i]] + 1
                record[arr[i]] = i
                length = i - start + 1
            else:
                record[arr[i]] = i
                length += 1
        lengths.append(length)
        return max(lengths)

二叉树的层次遍历

在这里插入图片描述
就是普通的队列依次记录每一层的节点,注意本题没有做到bugfree的原因是变量又写错!!node.left 不是root.left

from collections import deque
class Solution:
    def levelOrder(self , root ):
        # write code here
        if not root:
            return []
        queue = deque()
        queue.append(root)
        result = []
        
        def sub_level(queue):
            res = deque()
            out = []
            while queue:
                node = queue.popleft()
                out.append(node.val)
                if node.left:
                    res.append(node.left)
                if node.right:
                    res.append(node.right)
            return res, out
        while queue:
            queue, out = sub_level(queue)
            result.append(out)
        return result

二分

题目描述
请实现有重复数字的升序数组的二分查找。
输出在数组中第一个大于等于查找值的位置,如果数组中不存在这样的数,则输出数组长度加一。
示例1 输入 5,4,[1,2,4,4,5] 返回值 3

本题很简单,没有bugfree的原因:题意没有看清,是第一个大于等于查找值的位置,并且这个位置是从1开始的。 所以本处对二分进行了变体,找到对应的目标v也不返回,继续缩小范围,right永远代表的是小于查找值的位置。即使到了最后一位,就说明不存在大于等于查找值的位置。

# 题意开始看错了!!!--- 是  第一个大于等于 ---- 输出的是位置,并且是从1开始的
class Solution:
    def upper_bound_(self , n , v , a ):
        # write code here
        if not a:
            return n + 1
        def divide_select(left, right):
            while left <= right:
                mid = (left + right)//2
                if a[mid] > v:
                    right = mid - 1
                elif a[mid] < v:
                    left = mid + 1
                else:
                    right = mid - 1
            return right
        
        left = 0
        right = n-1
        res = divide_select(left, right)
        return res + 2   # 直接返回res+1+1就可以了,+1是因为下一个就是大于等于查找值,再加1是因为序号从1开始。
        #if res + 1 <= n-1:
        #    return res + 2
        #else:
        #    return n+1

x的平方根

题目描述
实现函数 int sqrt(int x).
计算并返回x的平方根(向下取整)

第一个省事是明确到,大于等于4的情况下,x//2 的平方都是大于x的。
关键是二分可以省事

class Solution:
    def sqrt(self , x ):
        # write code here
        def divide_select(x, right, left=1):
            while left <= right:
                mid = (left + right)//2
                if mid * mid > x:
                    right = mid - 1
                elif mid * mid < x:
                    left = mid + 1
                else:
                    return mid
            return left - 1
        
        if x == 0:
            return 0
        if x == 1 or x == 2 or x == 3:
            return 1
        
        return divide_select(x, x//2)
    

142. 环形链表 II – 环的入口

给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。注意,pos 仅仅是用于标识环的情况,并不会作为参数传递到函数中。
说明:不允许修改给定的链表。
进阶:你是否可以使用 O(1) 空间解决此题?

第一种方法空间复杂度是O(n).

class Solution(object):
    def detectCycle(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        record = {
    
    }
        node = head
        while node:
            if node in record:
                return node
            record[node] = 1
            node = node.next
        return None

第二种方法的空间复杂度是O(1),做法关键是发现公式的规律。
在这里插入图片描述

设置两个指针,fast每次走两步,slow走一步,相遇的时候 ,fast走了n*(b+c)+a +b的距离,slow走了a + b的距离,并且 fast的距离是slow距离的两倍。

可以得到 a = c + (n-1)*(b+c)
所以,再重新安排一个新的指针,从头节点开始往后,当last节点走了a步的时候,slow节点就走了c+(n-1)(b+c),所以必定在入口处相遇。

class Solution(object):
    def detectCycle(self, head):
        # 指针移动解决:
        fast = head
        slow = head
        last = head
        sign = 0
        while fast:
            if sign:
                last = last.next
            fast = fast.next
            if not fast:
                return None
            fast = fast.next
            slow = slow.next
            if slow == fast:
                sign = 1
            if last == slow:
                return last
        return None

第三种方法我觉得比较容易理解:
直线部分记作a,环的长度记作N。
那么先让fast指针走N,再一起走,他们就会在入口处相遇,为什么呢?因为fast走了N之后,总的路剩下a,再走a就走完所有,回到环的起点,而slow同时走了a,如图,相遇。
所以重点是找到N,方法,fast走一步,slow走两步,相遇的时候,记住这个节点,slow继续走,直到再次回到这个节点,说明一圈节点到了。
在这里插入图片描述

子数组的最大累加和

在这里插入图片描述

# 只要是前面正的就可加进来。
class Solution:
    def maxsumofSubarray(self , arr ):
        # write code here
        if not arr:
            return 0
        sum = 0
        largest = 0
        for i in arr:
            if sum <= 0:
                if i < 0:
                    continue
                else:
                    sum = 0
                    sum += i
            else:
                if i < 0:
                    if sum > largest:
                        largest = sum
                sum += i
        if sum > largest:
            largest = sum
        return largest

链表中的节点每K个一组翻转

在这里插入图片描述
在这里插入图片描述
其实还是比较明显,先计算出总链表长度; 然后每k个翻转,要注意翻转之后,达到k的时候,又是新的一波,第一个节点不翻转,此时需要重新链接,上一次的末尾,链接上此时的头节点。也就是last_node。每一次操作的就是node2,node1是记录上一个节点,node3是记录下一个节点,因为转向之后必定找不到原来的next了。

class Solution:
    def reverseKGroup(self , head , k ):
        # write code here
        res = head
        num = 0
        while res:
            num += 1
            res = res.next
        if num < k:
            return head  # 需要先清楚链表的长度,以避免尾部而白翻转
        
        new_head = head
        node1 = head
        node2 = head.next
        count = 1
        done = 0
        
        first = ListNode(1)
        first.next = head
        last_head= first
        
        while count <= k:  # 本题的漏洞在原先的判断条件是while count <= k and node2:
                            # 这样导致了如果刚好整除k的情况下,最后一部分没有链接上就结束了。
            if count == 1:
                head1 = node1
            if count == k:
                done += 1
                if done == 1:
                    new_head = node1
                last_head.next = node1
                head1.next = node2
                node1 = node2
                if not node1:    # 进行每一个next都最好先判断 本节点是否存在!!
                    break
                node2 = node1.next
                count = 1
                last_head = head1
                if done >= num // k:
                    break
            else:
                node3 = node2.next
                node2.next = node1
                node1 = node2
                node2 = node3
                count += 1
            
        return new_head

最近的公共祖先节点

题目描述
给定一棵二叉树以及这棵树上的两个节点 o1 和 o2,请找到 o1 和 o2 的最近公共祖先节点。
示例1
输入 [3,5,1,6,2,0,8,#,#,7,4],5,1
返回值 3

注意牛客的这个题要注意好 输入的值 代表的是什么,是节点还是值。
这道题开始想的解法没有下述简单,主要是通过查询o1,o2的存在,深度优先,如果查询到了,则返回1,否则返回0,直到两个都是1的时候,说明此时的节点就是最近的公共祖先节点。

下面的简单解法其实差不多,时间复杂度O(n)–节点数;但是比较简洁。–如果找到了就返回root,否则是一直返回None的。并且也节省了,因为如果只遍历到一个的话,那么这个点必定也是祖先节点,不需要再往下。

# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
# @param root TreeNode类 
# @param o1 int整型 
# @param o2 int整型 
# @return int整型

class Solution:
    def lowestCommonAncestor(self , root , o1 , o2 ):
        if not root:
            return 
        
        def dfs(root , o1 , o2):
            if not root or root.val == o1 or root.val == o2:
                return root
            left = dfs(root.left, o1, o2)
            right = dfs(root.right, o1, o2)
            if not left:
                return right
            if not right:
                return left
            return root    # 因为是后序遍历,所以return的就是第一个最近的公共节点。
        
        return dfs(root , o1 , o2).val
import copy
class Solution:
    def lowestCommonAncestor(self , root , o1 , o2 ):
        # write code here
        record = []
        record1 = 0
        record2 = 0
        ######## 注意是后续遍历。
        def dfs(root, record1, record2):
            if not root:
                return record1, record2
            
            res1, res2 = dfs(root.left, record1, record2)
            record1, record2 = dfs(root.right, record1, record2)
            
            if root.val == o1:
                record1 = 1

            if root.val == o2:
                record2 =1

            if record1 and record2:
                record.append(root)
                return record1, record2
            
            record1 = record1 or res1
            record2 = record2 or res2
            
            if record1 and record2:
                record.append(root)

            return record1, record2    # 返回总是容易漏掉~~~

        dfs(root, record1, record2)
        return record[0].val

猜你喜欢

转载自blog.csdn.net/caihuanqia/article/details/112638279
今日推荐