【CSDN每日一题】To Be Or Not To Be

请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(push、top、pop 和 empty)。

实现 MyStack 类:

void push(int x) 将元素 x 压入栈顶。
int pop() 移除并返回栈顶元素。
int top() 返回栈顶元素。
boolean empty() 如果栈是空的,返回 true ;否则,返回 false 。

注意:

  • 你只能使用队列的基本操作 —— 也就是 push to backpeek/pop from frontsizeis empty 这些操作。
  • 你所使用的语言也许不支持队列。 你可以使用 list (列表)或者 deque(双端队列)来模拟一个队列 , 只要是标准的队列操作即可。

示例:

输入:
[“MyStack”, “push”, “push”, “top”, “pop”, “empty”]
[[], [1], [2], [], [], []]
输出:
[null, null, null, 2, 2, false]

解释:
MyStack myStack = new MyStack();
myStack.push(1);
myStack.push(2);
myStack.top(); // 返回 2
myStack.pop(); // 返回 2
myStack.empty(); // 返回 False

提示:

  • 1 <= x <= 9
  • 最多调用100 次 push、pop、top 和 empty
  • 每次调用 pop 和 top 都保证栈不为空

进阶:你能否实现每种操作的均摊时间复杂度为 O(1) 的栈?换句话说,执行 n 个操作的总时间复杂度 O(n) ,尽管其中某个操作可能需要比其他操作更长的时间。你可以使用两个以上的队列。

#include <bits/stdc++.h>
using namespace std;
class MyStack
{
public:
    MyStack()
    {
    }
    void push(int x)
    {
        std::queue<int> temp_queue;
        temp_queue.push(x);
        while (!_data.empty())
        {
            temp_queue.push(_data.front());
            _data.pop();
        }
        while (!temp_queue.empty())
        {
            _data.push(temp_queue.front());
            temp_queue.pop();
        }
    }
    int pop()
    {
        int x = _data.front();
        _data.pop();
        return x;
    }
    int top()
    {
        return _data.front();
    }
    bool empty()
    {
        return _data.empty();
    }
private:
    std::queue<int> _data;
};
生成100个2位随机正整数,按每行十个输出,并求出个位数字分别为0,1,2,3,4,5,6,7,8,9的正整数的个数
import random
def fun():
    random_list = [random.randint(10, 99) for n in range(100)]
    statistics = {n: 0 for n in range(10)}
    for index, x in enumerate(random_list):
        print(x, end=' ')
        statistics[int(x % 10)] = statistics[int(x % 10)] + 1
        if ((index + 1) % 10 == 0):
            print()
    print(statistics)
if __name__ == '__main__':
    fun()

问题描述:

给定一个整数数组 nums,请找出数组中乘积最大的连续子数组(该子数组中至少包含一个数字),并返回该子数组所对应的乘积。

示例 1:

输入: [2,3,-2,4]
输出: 6
解释: 子数组 [2,3] 有最大乘积 6。

示例 2:

输入: [-2,0,-1]
输出: 0
解释: 结果不能为 2, 因为 [-2,-1] 不是子数组。

class Solution:
    def maxProduct(self, nums: List[int]) -> int:
        if len(nums) == 0:
            return 0
        length = len(nums)
        dp = [[0] * 2 for _ in range(length)]
        dp[0][0] = nums[0]
        dp[0][1] = nums[0]
        for i in range(1, length):
            if nums[i] > 0:
                dp[i][0] = min(nums[i], dp[i - 1][0] * nums[i])
                dp[i][1] = max(nums[i], dp[i - 1][1] * nums[i])
            else:
                dp[i][0] = min(nums[i], dp[i - 1][1] * nums[i])
                dp[i][1] = max(nums[i], dp[i - 1][0] * nums[i])
        res = dp[0][1]
        for i in range(1, length):
            res = max(res, dp[i][1])
        return res
给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中,返回 true ;否则,返回 false 。

单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。

示例 1:
在这里插入图片描述

输入:board = [[“A”,“B”,“C”,“E”],[“S”,“F”,“C”,“S”],[“A”,“D”,“E”,“E”]], word = “ABCCED”
输出:true
示例 2:
在这里插入图片描述

输入:board = [[“A”,“B”,“C”,“E”],[“S”,“F”,“C”,“S”],[“A”,“D”,“E”,“E”]], word = “SEE”
输出:true
示例 3:
在这里插入图片描述

输入:board = [[“A”,“B”,“C”,“E”],[“S”,“F”,“C”,“S”],[“A”,“D”,“E”,“E”]], word = “ABCB”
输出:false
提示:

  • m == board.length
  • n = board[i].length
  • 1 <= m, n <= 6
  • 1 <= word.length <= 15
  • board 和 word 仅由大小写英文字母组成

进阶:你可以使用搜索剪枝的技术来优化解决方案,使其在 board 更大的情况下可以更快解决问题?

class Solution(object):
    def exist(self, board, word):
        """
        :type board: List[List[str]]
        :type word: str
        :rtype: bool
        """
        check_board = [[True] * len(board[0]) for _ in range(len(board))]
        for i in range(len(board)):
            for j in range(len(board[0])):
                if board[i][j] == word[0] and check_board:
                    check_board[i][j] = False
                    res = self.check_exist(check_board, board, word, 1, len(word), i, j)
                    if res:
                        return True
                    check_board[i][j] = True
        return False
    def check_exist(self, check_board, board, word, index, ls, row, col):
        if index == ls:
            return True
        for temp in [(0, 1),(0, -1),(1, 0),(-1, 0)]:
            curr_row = row + temp[0]
            curr_col = col + temp[1]
            if curr_row >= 0 and curr_row < len(board) and curr_col >= 0 and curr_col < len(board[0]):
                if check_board[curr_row][curr_col] and board[curr_row][curr_col] == word[index]:
                    check_board[curr_row][curr_col] = False
                    res = self.check_exist(check_board, board, word, index + 1, len(word), curr_row, curr_col)
                    if res:
                        return res
                    check_board[curr_row][curr_col] = True
        return False
if __name__ == "__main__":
    s = Solution()
    print (s.exist(board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "ABCCED"))

矩阵置零

给定一个 m x n 的矩阵,如果一个元素为 0,则将其所在行和列的所有元素都设为 0。请使用 原地算法 算法。

进阶:

一个直观的解决方案是使用 O(mn) 的额外空间,但这并不是一个好的解决方案。

一个简单的改进方案是使用 O(m + n) 的额外空间,但这仍然不是最好的解决方案。

你能想出一个仅使用常量空间的解决方案吗?

示例 1:
在这里插入图片描述

输入:

matrix = [[1,1,1],[1,0,1],[1,1,1]]

输出:

[[1,0,1],[0,0,0],[1,0,1]]

示例 2:
在这里插入图片描述

输入:

matrix = [[0,1,2,0],[3,4,5,2],[1,3,1,5]]

输出:

[[0,0,0,0],[0,4,5,0],[0,3,1,0]]

提示:

  • m == matrix.length
  • n == matrix[0].length
  • 1 <= m, n <= 200
  • -2^31 <= matrix[i][j] <= 2^31 - 1

解题思路:

这道题要求原地修改矩阵,即不使用额外的空间。我们可以使用第一行和第一列来记录每一行和每一列是否需要被置零。具体步骤如下:

  1. 遍历矩阵,如果某个元素 matrix[i][j] 为零,将 matrix[i][0]matrix[0][j] 设置为零,用于标记该行和该列需要被置零。

  2. 再次遍历矩阵,如果 matrix[i][0]matrix[0][j] 为零,将 matrix[i][j] 置零。

  3. 最后,根据第一行和第一列的标记,将第一行和第一列的元素置零。

这样,我们在不使用额外空间的情况下,成功地将矩阵中的零元素进行了标记和置零。以下是具体的代码实现:

class Solution {
    public void setZeroes(int[][] matrix) {
        int[] xNum = new int[matrix[0].length];
        int[] yNum = new int[matrix.length];
        for (int i = 0; i < matrix.length; i++) {
            for (int j = 0; j < matrix[i].length; j++) {
                if (matrix[i][j] == 0) {
                    xNum[j] = 1;
                    yNum[i] = 1;
                }
            }
        }
        for (int i = 0; i < matrix.length; i++) {
            for (int j = 0; j < matrix[i].length; j++) {
                if (xNum[j] == 1 || yNum[i] == 1) {
                    matrix[i][j] = 0;
                }
            }
        }
    }
}   

这个算法的时间复杂度为 O(mn),空间复杂度为 O(1)。

单词搜索 II

给定一个 m x n 二维字符网格 board 和一个单词(字符串)列表 words,找出所有同时在二维网格和字典中出现的单词。

单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中相邻单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母在一个单词中不允许被重复使用。

示例 1:

在这里插入图片描述

输入:

board = [["o","a","a","n"],["e","t","a","e"],["i","h","k","r"],["i","f","l","v"]]
words = ["oath","pea","eat","rain"]

输出:

["eat","oath"]

示例 2:

在这里插入图片描述

输入:

board = [["a","b"],["c","d"]]
words = ["abcb"]

输出:

[]

提示:

  • m == board.length
  • n == board[i].length
  • 1 <= m, n <= 12
  • board[i][j] 是一个小写英文字母
  • 1 <= words.length <= 3 * 10^4
  • 1 <= words[i].length <= 10
  • words[i] 由小写英文字母组成
  • words 中的所有字符串互不相同

解题思路:

这道题可以使用字典树(Trie)结构来进行搜索。首先,将 words 中的单词构建成一个 Trie 树。然后,遍历二维网格 board 中的每个单元格,从每个单元格出发,通过 DFS 深度优先搜索来查找可能的单词。

具体步骤如下:

  1. 构建 Trie 树:遍历 words 中的每个单词,将其插入 Trie 树中。同时,可以为每个 Trie 节点存储一个额外的标记,表示该节点对应的单词是否在 words 中。

  2. 遍历二维网格 board:遍历每个单元格,以每个单元格为起点,进行 DFS 搜索。在搜索过程中,需要判断当前字符是否是 Trie 树中某个单词的前缀,如果不是,则可以提前终止搜索。

  3. DFS 搜索:从当前单元格出发,首先检查当前字符是否在 Trie 树中,如果不在,则返回。否则,将当前字符标记为已访问,然后递归地搜索其相邻的未访问过的单元格。在搜索过程中,需要维护一个字符串,记录当前路径上的字符。

  4. 收集结果:如果当前路径上的字符串在 Trie 树中,表示找到一个匹配的单词,将其添加到结果集中。需要注意的是,在结果集中添加后,需要将 Trie 树中的标记清除,以避免重复添加。

以下是具体的代码实现:

class Solution {
    static int[][] d = new int[][] { { -1, 0 }, { 1, 0 }, { 0, -1 }, { 0, 1 } };
    static Map<String, Boolean> notExistWords = new HashMap<>();
    public List<String> findWords(char[][] board, String[] words) {
        List<String> ans = new ArrayList<>();
        Arrays.sort(words);
        notExistWords.clear();
        for (int i = 0; i < words.length; i++) {
            String word = words[i];
            if (i > 0 && word.equals(words[i - 1]))
                continue;
            boolean notExistFlag = false;
            for (int j = 1; j < word.length(); j++) {
                if (notExistWords.containsKey(word.substring(0, j + 1))) {
                    notExistFlag = true;
                    break;
                }
            }
            if (notExistFlag)
                continue;
            if (exist(board, word)) {
                ans.add(word);
            } else {
                notExistWords.put(word, false);
            }
        }
        return ans;
    }
    public boolean exist(char[][] board, String word) {
        int m = board.length;
        if (m == 0)
            return false;
        int n = board[0].length;
        if (n == 0)
            return false;
        if (word.equals(""))
            return true;
        boolean[][] f = new boolean[m][n];
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (word.charAt(0) == board[i][j]) {
                    f[i][j] = true;
                    boolean flag = dfs(i, j, 1, board, word, m, n, f);
                    if (flag)
                        return true;
                    f[i][j] = false;
                }
            }
        }
        return false;
    }
    private boolean dfs(int i, int j, int k, char[][] board, String word, int m, int n, boolean[][] f) {
        if (k == word.length()) {
            return true;
        }
        for (int l = 0; l < 4; l++) {
            if (i + d[l][0] < m && j + d[l][1] < n && i + d[l][0] >= 0 && j + d[l][1] >= 0
                    && board[i + d[l][0]][j + d[l][1]] == word.charAt(k) && !f[i + d[l][0]][j + d[l][1]]) {
                f[i + d[l][0]][j + d[l][1]] = true;
                boolean flag = dfs(i + d[l][0], j + d[l][1], k + 1, board, word, m, n, f);
                if (flag)
                    return true;
                f[i + d[l][0]][j + d[l][1]] = false;
            }
        }
        return false;
    }
}

Excel表列序号

给定一个字符串 columnTitle ,表示 Excel 表格中的列名称。返回该列名称对应的列序号。

例如,

A -> 1
B -> 2
C -> 3

Z -> 26
AA -> 27
AB -> 28

示例 1:

输入: columnTitle = "A"
输出: 1

示例 2:

输入: columnTitle = "AB"
输出: 28

示例 3:

输入: columnTitle = "ZY"
输出: 701

示例 4:

输入: columnTitle = "FXSHRXW"
输出: 2147483647

提示:

  • 1 <= columnTitle.length <= 7
  • columnTitle 仅由大写英文组成
  • columnTitle 在范围 [“A”, “FXSHRXW”] 内
class Solution {
    public int titleToNumber(String s) {
        char[] charArray = s.toCharArray();
        int res = 0;
        for (int i = 0; i < charArray.length; i++) {
            res = res * 26 + (charArray[i] - 'A' + 1);
        }
        return res;
    }
}

删除链表中的元素

给定一个链表的头节点 head 和一个整数 val,请你删除链表中所有满足 Node.val == val 的节点,并返回新的头节点。

示例

在这里插入图片描述

示例 1

输入:head = [1,2,6,3,4,5,6], val = 6

输出:[1,2,3,4,5]

示例 2

输入:head = [], val = 1

输出:[]

示例 3

输入:head = [7,7,7,7], val = 7

输出:[]

提示

  • 列表中的节点数目在范围 [0, 10^4] 内
  • 1 <= Node.val <= 50
  • 0 <= val <= 50
public class ListNode {
    int val;
    ListNode next;
    ListNode(int x) {
        val = x;
    }
}
class Solution {
    public ListNode removeElements(ListNode head, int val) {
        ListNode top = new ListNode(0);
        top.next = head;
        ListNode pre = top;
        ListNode temp = head;
        while (temp != null) {
            if (temp.val == val)
                pre.next = temp.next;
            else
                pre = temp;
            temp = temp.next;
        }
        return top.next;
    }
}

城市天际线

城市的天际线是从远处观看该城市中所有建筑物形成的轮廓的外部轮廓。给你所有建筑物的位置和高度,请返回由这些建筑物形成的天际线。

每个建筑物的几何信息由数组 buildings 表示,其中三元组 buildings[i] = [lefti, righti, heighti] 表示:

  • lefti 是第 i 座建筑物左边缘的 x 坐标。
  • righti 是第 i 座建筑物右边缘的 x 坐标。
  • heighti 是第 i 座建筑物的高度。

天际线应该表示为由 “关键点” 组成的列表,格式 [[x1,y1],[x2,y2],…] ,并按 x 坐标 进行排序。关键点是水平线段的左端点。列表中最后一个点是最右侧建筑物的终点,y 坐标始终为 0 ,仅用于标记天际线的终点。此外,任何两个相邻建筑物之间的地面都应被视为天际线轮廓的一部分。

注意:输出天际线中不得有连续的相同高度的水平线。例如 […[2 3], [4 5], [7 5], [11 5], [12 7]…] 是不正确的答案;三条高度为 5 的线应该在最终输出中合并为一个:[…[2 3], [4 5], [12 7], …]

示例 1:

在这里插入图片描述

输入
buildings = [[2,9,10],[3,7,15],[5,12,12],[15,20,10],[19,24,8]]
输出
[[2,10],[3,15],[7,12],[12,0],[15,10],[20,8],[24,0]]
解释
  • 图 A 显示输入的所有建筑物的位置和高度,
  • 图 B 显示由这些建筑物形成的天际线。图 B 中的红点表示输出列表中的关键点。

示例 2:

输入
buildings = [[0,2,3],[2,5,3]]
输出
[[0,3],[5,0]]

提示

  • 1 <= buildings.length <= 10^4
  • 0 <= lefti < righti <= 2^31 - 1
  • 1 <= heighti <= 2^31 - 1
  • buildings 按 lefti 非递减排序
class Solution {
    public List<List<Integer>> getSkyline(int[][] buildings) {
        int n = buildings.length, m = n << 1;
        List<List<Integer>> ans = new ArrayList<List<Integer>>();
        int[] boundaries = new int[m];
        for (int i = 0; i < n; i++) {
            boundaries[i << 1] = buildings[i][0];
            boundaries[(i << 1) + 1] = buildings[i][1];
        }
        Arrays.sort(boundaries);
        PriorityQueue<int[]> pq = new PriorityQueue<int[]>((a, b) -> b[1] - a[1]);
        int building = 0;
        for (int i = 0; i < m; i++) {
            if (i > 0 && boundaries[i - 1] == boundaries[i])
                continue;
            while (building < n && buildings[building][0] <= boundaries[i])
                pq.offer(new int[] { buildings[building][1], buildings[building++][2] });
            while (!pq.isEmpty() && pq.peek()[0] <= boundaries[i])
                pq.poll();
            int height = (pq.isEmpty()) ? 0 : pq.peek()[1];
            if (ans.size() == 0 || height != ans.get(ans.size() - 1).get(1))
                ans.add(Arrays.asList(boundaries[i], height));
        }
        return ans;
    }
}

生成螺旋矩阵的示例:
在这里插入图片描述

示例 1:

输入: n = 3

输出:

[
 [ 1, 2, 3],
 [ 8, 9, 4],
 [ 7, 6, 5]
]

示例 2:

输入: n = 1

输出: [[1]]

提示:

1 <= n <= 20

package LeetCode;
public class GenerateMatrix {
    public int[][] generateMatrix(int n) {
        int[][] res = new int[n][n];
        if (n == 0) {
            return res;
        }
        int left = 0;
        int right = n - 1;
        int up = 0;
        int down = n - 1;
        int i = 1;
        while (i <= n * n) {
            for (int col = left; col <= right; col++) {
                res[up][col] = i;
                i++;
            }
            up++;
            if (i <= n * n) {
                for (int j = up; j <= down; j++) {
                    res[j][right] = i;
                    i++;
                }
                right--;
            }
            if (i <= n * n) {
                for (int j = right; j >= left; j--) {
                    res[down][j] = i;
                    i++;
                }
                down--;
            }
            if (i <= n * n) {
                for (int j = down; j >= up; j--) {
                    res[j][left] = i;
                    i++;
                }
                left++;
            }
        }
        return res;
    }
    public static void main(String[] args) {
        GenerateMatrix a = new GenerateMatrix();
        a.generateMatrix(3);
    }
}

实现 pow(x, n) 函数:

给定 x 和 n,计算 x 的 n 次幂。

示例 1:

输入:

x = 2.00000, n = 10

输出:

1024.00000

示例 2:

输入:

x = 2.10000, n = 3

输出:

9.26100

示例 3:

输入:

x = 2.00000, n = -2

输出:

0.25000

解释:

2^-2 = 1/(2^2) = 1/4 = 0.25

提示:

-100.0 < x < 100.0
-231 <= n <= 231-1
-104 <= x^n <= 104

public class Solution {
    public double myPow(double x, int n) {
        if (n < 0) {
            return 1 / pow(x, -n);
        } else {
            return pow(x, n);
        }
    }
    private double pow(double x, int n) {
        if (n == 0) {
            return 1.0;
        }
        if (n == 1) {
            return x;
        }
        double val = pow(x, n / 2);
        if (n % 2 == 0) {
            return val * val;
        } else {
            return val * val * x;
        }
    }
}

最小路径和问题:

给定一个非负整数的 m x n 网格 grid,请找出一条从左上角到右下角的路径,使得路径上的数字总和最小。每次只能向下或向右移动一步。

示例 1:
在这里插入图片描述

输入:

grid = [
    [1,3,1],
    [1,5,1],
    [4,2,1]
]

输出:

7

解释:

路径 1→3→1→1→1 的总和最小。

示例 2:

输入:

grid = [
    [1,2,3],
    [4,5,6]
]

输出:

12

提示:

  • m == grid.length
  • n == grid[i].length
  • 1 <= m, n <= 200
  • 0 <= grid[i][j] <= 100
class Solution {
    public int minPathSum(int[][] grid) {
        int m = grid.length;
        int n = grid[0].length;
        int sum = 0;
        if (m < 1 || n < 1)
            return 0;
        if (m == 1) {
            for (int i = 0; i < n; i++) {
                sum = sum + grid[0][i];
            }
            return sum;
        }
        if (n == 1) {
            for (int i = 0; i < m; i++) {
                sum = sum + grid[i][0];
            }
            return sum;
        }
        int[][] dp = new int[m][n];
        dp[0][0] = grid[0][0];
        for (int k = 1; k < m; k++) {
            dp[k][0] = grid[k][0] + dp[k - 1][0];
        }
        for (int l = 1; l < n; l++) {
            dp[0][l] = grid[0][l] + dp[0][l - 1];
        }
        for (int k = 1; k < m; k++) {
            for (int l = 1; l < n; l++) {
                dp[k][l] = grid[k][l] + Math.min(dp[k - 1][l], dp[k][l - 1]);
            }
        }
        return dp[m - 1][n - 1];
    }
}

设计一个支持平均时间复杂度 O(1) 的数据结构:

设计一个数据结构,支持以下操作:

  • insert(val):向集合中插入元素 val。
  • remove(val):当 val 存在时,从集合中移除一个 val。
  • getRandom:从现有集合中随机获取一个元素,每个元素被返回的概率应该与其在集合中的数量呈线性相关。

示例:

// 初始化一个空的集合。
RandomizedCollection collection = new RandomizedCollection();

// 向集合中插入 1 。返回 true 表示集合不包含 1 。
collection.insert(1);

// 向集合中插入另一个 1 。返回 false 表示集合包含 1 。集合现在包含 [1,1] 。
collection.insert(1);

// 向集合中插入 2 ,返回 true 。集合现在包含 [1,1,2] 。
collection.insert(2);

// getRandom 应当有 2/3 的概率返回 1 ,1/3 的概率返回 2 。
collection.getRandom();

// 从集合中删除 1 ,返回 true 。集合现在包含 [1,2] 。
collection.remove(1);

// getRandom 应有相同概率返回 1 和 2 。
collection.getRandom();

这个数据结构需要在插入、删除和获取随机元素这三个操作上都满足平均时间复杂度 O(1) 的要求。

class RandomizedCollection {
    private Map<Integer, Set<Integer>> map;
    private List<Integer> list;
    private Random random;
    private int size = 0;
    public RandomizedCollection() {
        map = new HashMap<>();
        list = new ArrayList<>();
        random = new Random();
    }
    public boolean insert(int val) {
        if (map.containsKey(val)) {
            Set<Integer> indexes = map.get(val);
            list.add(size, val);
            indexes.add(size);
            size++;
            return false;
        } else {
            Set<Integer> indexes = new HashSet<>();
            map.put(val, indexes);
            list.add(size, val);
            indexes.add(size);
            size++;
            return true;
        }
    }
    public boolean remove(int val) {
        if (!map.containsKey(val)) {
            return false;
        }
        Set<Integer> indexes = map.get(val);
        if (list.get(size - 1) == val) {
            indexes.remove(size - 1);
            size--;
        } else {
            Iterator<Integer> it = indexes.iterator();
            int index = it.next();
            it.remove();
            int last = list.get(size - 1);
            list.set(index, last);
            Set<Integer> set = map.get(last);
            set.remove(size - 1);
            set.add(index);
            size--;
        }
        if (indexes.size() == 0) {
            map.remove(val);
        }
        return true;
    }
    public int getRandom() {
        return list.get(random.nextInt(size));
    }
}
/**
 * Your RandomizedCollection object will be instantiated and called as such:
 * RandomizedCollection obj = new RandomizedCollection();
 * boolean param_1 = obj.insert(val);
 * boolean param_2 = obj.remove(val);
 * int param_3 = obj.getRandom();
 */

矩形区域不超过 K 的最大数值和

题目:

给定一个 m x n 的矩阵 matrix 和一个整数 k ,找出并返回矩阵内部矩形区域的不超过 k 的最大数值和。

示例 1:
在这里插入图片描述

输入:matrix = [[1,0,1],[0,-2,3]], k = 2
输出:2
解释:蓝色边框圈出来的矩形区域 [[0, 1], [-2, 3]] 的数值和是 2,且 2 是不超过 k 的最大数字(k = 2)。

示例 2:

输入:matrix = [[2,2,-1]], k = 3
输出:3

提示:

  • m == matrix.length
  • n == matrix[i].length
  • 1 <= m, n <= 100
  • -100 <= matrix[i][j] <= 100
  • -10^5 <= k <= 10^5

进阶: 如果行数远大于列数,该如何设计解决方案?

import bisect
class Solution:
    def maxSumSubmatrix(self, matrix: List[List[int]], k: int) -> int:
        m = len(matrix)
        Row, Col = len(matrix), len(matrix[0])
        res = float("-inf")
        for ru in range(Row):
            col_sum = [0 for _ in range(Col)]
            for rd in range(ru, Row):
                for c in range(Col):
                    if matrix[rd][c] == k:
                        return k
                    col_sum[c] += matrix[rd][c]
                presum = [0]
                cur_sum = 0
                for colsum in col_sum:
                    cur_sum += colsum
                    idx = bisect.bisect_left(presum, cur_sum - k)
                    if idx < len(presum):
                        res = max(res, cur_sum - presum[idx])
                        if res == k:
                            return k
                    bisect.insort(presum, cur_sum)
        return res

冒泡排序

用冒泡排序编写一个函数,允许接受多个数字的输入,不使用sort方法,给数字从小到大排序,最终输出从小到大的列表。

#!/usr/bin/python3
def bubbleSort(arr):
    n = len(arr)
    for i in range(n):
        for j in range(0, n-i-1):
            if arr[j] > arr[j+1] :
                arr[j], arr[j+1] = arr[j+1], arr[j]
x=input("请输入数字,空格分隔:")
xlist=x.split(" ")
arr = [int(xlist[i]) for i in range(len(xlist))]
bubbleSort(arr)
print ("排序后的数组:")
for i in range(len(arr)):
    print ("%d" %arr[i])

判断快乐数

编写一个算法来判断一个数 n 是不是快乐数。

快乐数的定义为:

  • 对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。
  • 然后重复这个过程直到这个数变为 1,也可能是无限循环但始终变不到 1。
  • 如果可以变为 1,那么这个数就是快乐数。

如果 n 是快乐数就返回 true ;不是,则返回 false 。

示例

示例 1

输入:19

输出:true

解释:

  • 1 2 + 9 2 = 82 1^2 + 9^2 = 82 12+92=82
  • 8 2 + 2 2 = 68 8^2 + 2^2 = 68 82+22=68
  • 6 2 + 8 2 = 100 6^2 + 8^2 = 100 62+82=100
  • 1 2 + 0 2 + 0 2 = 1 1^2 + 0^2 + 0^2 = 1 12+02+02=1
示例 2

输入:n = 2

输出:false

提示

1 ≤ n ≤ 2 31 − 1 1 \le n \le 2^{31} - 1 1n2311

class Solution(object):
    def isHappy(self, n):
        """
        :type n: int
        :rtype: bool
        """
        d = {}
        while True:
            l = list(map(int, list(str(n))))
            m = 0
            for i in l:
                m += i ** 2
            if m in d:
                print(d)
                return False
            if m == 1:
                print(d)
                return True
            d[m] = m
            n = m

删除有序数组中的重复项

给你一个有序数组 nums ,请你 原地删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。

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

说明:

为什么返回数值是整数,但输出的答案是数组呢?

请注意,输入数组是以「引用」方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。

你可以想象内部操作如下:

# nums 是以“引用”方式传递的。也就是说,不对实参做任何拷贝
int len = removeDuplicates(nums);

// 在函数里修改输入数组对于调用者是可见的。
// 根据你的函数返回的长度, 它会打印出数组中 该长度范围内 的所有元素。
for (int i = 0; i < len; i++) {
    print(nums[i]);
}
示例 1:

输入:nums = [1,1,2]

输出:2, nums = [1,2]

解释:函数应该返回新的长度 2 ,并且原数组 nums 的前两个元素被修改为 1, 2。不需要考虑数组中超出新长度后面的元素。

示例 2:

输入:nums = [0,0,1,1,1,2,2,3,3,4]

输出:5, nums = [0,1,2,3,4]

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

提示:
  • 0 <= nums.length <= 3 * 104
  • -104 <= nums[i] <= 104
  • nums 已按升序排列
class Solution(object):
    def removeDuplicates(self, nums):
        if len(nums) == 0:
            return 0
        left = 0
        for i in range(1, len(nums)):
            if nums[left] == nums[i]:
                continue
            else:
                left += 1
                nums[left] = nums[i]
        return left + 1
# %%
s = Solution()
print(s.removeDuplicates(nums = [1,1,2]))

计算出因子里面4和7的个数

输入一个正数n,计算出因子里面分别有几个4和7,输出因子中4和7的个位数

以下程序实现了这一功能,请你填补空白处内容:

n = int(input("输入数字:"))
factor = [n]   
num = 1
while num <= n/2+1:
    if n % num == 0:
        factor.append(num)
    num = num + 1
print(factor)
m = [str(i) for i in factor]
count4 = 0
count7 = 0
for i in m:
    if '4' in i:
        count4 += 1
        print('以4结尾的因子的个位数:', int(i)%10)
    if '7' in i:
        count7 += 1
        print('以7结尾的因子的个位数:', int(i)%10)
print('因子里面分别有{0}个4和{1}个7'.format(count4,count7))

#路径总和II
给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。

叶子节点 是指没有子节点的节点。

示例 1:

在这里插入图片描述

输入:root = [5,4,8,11,null,13,4,7,2,null,null,5,1],
targetSum = 22
输出:[[5,4,11,2],[5,8,4,5]]

示例 2

输入:root = [1,2,3], targetSum = 5
输出:[]

示例 3:

输入:root = [1,2], targetSum = 0
输出:[]

提示:

树中节点总数在范围 [0, 5000] 内
-1000 <= Node.val <= 1000
-1000 <= targetSum <= 1000

class Solution:
    def pathSum(self, root: TreeNode, sum: int) -> List[List[int]]:
        pathvalue = 0
        path = []
        result = []
        def preorder(node, pathvalue, sum, path, result):
            if node == None:
                return
            pathvalue += node.val
            path.append(node.val)
            if pathvalue == sum and node.left == None and node.right == None:
                result.append(list(path))  # 注意加list
            preorder(node.left, pathvalue, sum, path, result)
            preorder(node.right, pathvalue, sum, path, result)
            pathvalue -= node.val
            path.pop()
        preorder(root, pathvalue, sum, path, result)
        return result

最大子数组和

给定一个整数数组 nums,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

示例

示例 1

输入:nums = [-2,1,-3,4,-1,2,1,-5,4]

输出:6

解释:连续子数组 [4,-1,2,1] 的和最大,为 6

示例 2

输入:nums = [1]

输出:1

示例 3

输入:nums = [0]

输出:0

示例 4

输入:nums = [-1]

输出:-1

示例 5

输入:nums = [-100000]

输出:-100000

提示

  • 1 <= nums.length <= 3 * 104
  • -105 <= nums[i] <= 105

进阶

如果你已经实现复杂度为 O(n) 的解法,尝试使用更为精妙的分治法求解。

#include <bits/stdc++.h>
using namespace std;
class Solution
{
public:
    int maxSubArray(vector<int> &nums)
    {
        int sum = 0, max_sum = INT_MIN;
        for (int i = 0; i < nums.size(); i++)
        {
            if (sum < 0)
            {
                sum = nums[i];
            }
            else
            {
                sum += nums[i];
            }
            max_sum = max(sum, max_sum);
        }
        return max_sum;
    }
};

外观数列

给定一个正整数 n ,输出外观数列的第 n 项。

「外观数列」是一个整数序列,从数字 1 开始,序列中的每一项都是对前一项的描述。

你可以将其视作是由递归公式定义的数字字符串序列:

  • countAndSay(1) = “1”
  • countAndSay(n) 是对 countAndSay(n-1) 的描述,然后转换成另一个数字字符串。

前五项如下:

  1. 1
  2. 11
  3. 21
  4. 1211
  5. 111221

第一项是数字 1,描述前一项,这个数是 1 即 “ 一 个 1 ”,记作 “11”。描述前一项,这个数是 11 即 “ 二 个 1 ” ,记作 “21”。描述前一项,这个数是 21 即 “ 一 个 2 + 一 个 1 ” ,记作 “1211”。描述前一项,这个数是 1211 即 “ 一 个 1 + 一 个 2 + 二 个 1 ” ,记作 “111221”。

要描述一个数字字符串,首先要将字符串分割为最小数量的组,每个组都由连续的最多相同字符组成。然后对于每个组,先描述字符的数量,然后描述字符,形成一个描述组。要将描述转换为数字字符串,先将每组中的字符数量用数字替换,再将所有描述组连接起来。

示例

在这里插入图片描述

示例 1

输入:n = 1

输出:“1”

解释:这是一个基本样例。

示例 2

输入:n = 4

输出:“1211”

解释:

  • countAndSay(1) = “1”
  • countAndSay(2) = 读 “1” = 一 个 1 = “11”
  • countAndSay(3) = 读 “11” = 二 个 1 = “21”
  • countAndSay(4) = 读 “21” = 一 个 2 + 一 个 1 = “12” + “11” = “1211”

提示

1 <= n <= 30

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

static void parse(char *input, char *output)
{
	char *p = input;
	char *q = output;
	while (*p != '\0')
	{
		int count = 1;
		while (p[0] == p[1])
		{
			count++;
			p++;
		}
		int n = 0;
		while (count > 0)
		{
			n += count % 10;
			count /= 10;
		}
		while (n > 0)
        {
	        *q++ = (n % 10) + '0';
	        n /= 10;
        }
		*q++ = p[0];
		p++;
	}
	*q = '\0';
}

static char *countAndSay(int n)
{
	if (n < 1)
	{
		return NULL;
	}
	char *result;
	char *prev = malloc(10000);
	char *next = malloc(10000);
	strcpy(prev, "1");
	if (n == 1)
	{
		return prev;
	}
	int i;
	for (i = 2; i <= n; i++)
	{
		if (i & 0x1)
		{
			parse(next, prev);
			result = prev;
		}
		else
		{
			parse(prev, next);
			result = next;
		}
	}
	return result;
}

int main(int argc, char **argv)
{
	if (argc != 2)
	{
		fprintf(stderr, "Usage: ./test n\n");
		exit(-1);
	}
	printf("%s\n", countAndSay(atoi(argv[1])));
	return 0;
}

反转链表 II

给你单链表的头指针 head 和两个整数 leftright ,其中 left <= right 。请你反转从位置 left 到位置 right 的链表节点,返回反转后的链表。

示例 1

在这里插入图片描述

输入:head = [1,2,3,4,5], left = 2, right = 4
输出:[1,4,3,2,5]

示例 2

输入:head = [5], left = 1, right = 1
输出:[5]

提示

  • 链表中节点数目为 n
  • 1 <= n <= 500
  • -500 <= Node.val <= 500
  • 1 <= left <= right <= n

进阶

你可以使用一趟扫描完成反转吗?

#include <stdio.h>
#include <stdlib.h>
struct ListNode
{
	int val;
	struct ListNode *next;
};
static struct ListNode *reverseBetween(struct ListNode *head, int m, int n)
{
	int i;
	struct ListNode dummy;
	struct ListNode *prev = &dummy;
	prev->next = head;
	for (i = 1; i < m; i++)
	{
		prev = prev->next;
	}
	struct ListNode *p = prev->next;
	for (i = m; i < n; i++)
	{
		struct ListNode *q = p->next;
		p->next = q->next;
        q->next = prev->next;
        prev->next = q;
	}
	return dummy.next;
}
int main(int argc, char **argv)
{
	if (argc < 3)
	{
		fprintf(stderr, "Usage: ./test m n 1 2 3...\n");
		exit(-1);
	}
	int i, count = argc - 3;
	struct ListNode dummy;
	struct ListNode *prev = &dummy;
	struct ListNode *p;
	for (i = 0; i < count; i++)
	{
		p = malloc(sizeof(*p));
		p->val = atoi(argv[i + 3]);
		p->next = NULL;
		prev->next = p;
		prev = p;
	}
	int m = atoi(argv[1]);
	int n = atoi(argv[2]);
	struct ListNode *head = reverseBetween(dummy.next, m, n);
	for (p = head; p != NULL; p = p->next)
	{
		printf("%d ", p->val);
	}
	printf("\n");
	return 0;
}

文本对齐

给定一个单词数组和一个长度 maxWidth,重新排版单词,使其成为每行恰好有 maxWidth 个字符,且左右两端对齐的文本。

你应该使用“贪心算法”来放置给定的单词;也就是说,尽可能多地往每行中放置单词。必要时可用空格 ' ' 填充,使得每行恰好有 maxWidth 个字符。

要求尽可能均匀分配单词间的空格数量。如果某一行单词间的空格不能均匀分配,则左侧放置的空格数要多于右侧的空格数。

文本的最后一行应为左对齐,且单词之间不插入额外的空格。

说明

  • 单词是指由非空格字符组成的字符序列。
  • 每个单词的长度大于 0,小于等于 maxWidth
  • 输入单词数组 words 至少包含一个单词。

示例 1

输入:

words = ["This", "is", "an", "example", "of", "text", "justification."]
maxWidth = 16

输出:

[
   "This    is    an",
   "example  of text",
   "justification.  "
]

示例 2

输入:

words = ["What","must","be","acknowledgment","shall","be"]
maxWidth = 16

输出:

[
  "What   must   be",
  "acknowledgment  ",
  "shall be        "
]

解释: 注意最后一行的格式应为 "shall be " 而不是 “shall be”
因为最后一行应为左对齐,而不是左右两端对齐,第二行同样为左对齐,这是因为这行只包含一个单词。

示例 3

输入:

words = ["Science","is","what","we","understand","well","enough","to","explain",
         "to","a","computer.","Art","is","everything","else","we","do"]
maxWidth = 20

输出:

[
  "Science  is  what we",
"understand      well",
  "enough to explain to",
  "a  computer.  Art is",
  "everything  else  we",
  "do                  "
]

以下是填写空白处内容的示例:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static void line_fill(char *line, int len, char **words, int *word_lens, int max_size,
					  int even_spaces, int remain_spaces, int start, int end)
{
	int i, j;
	char *p = line;
	for (i = start; i < end; i++)
	{
		memcpy(p, words[i], word_lens[i]);
		p += word_lens[i];
		if (i < end - 1)
		{
			for (j = 0; j < even_spaces; j++)
            {
	            *p++ = ' ';
            }
            if (remain_spaces > 0)
            {
	            *p++ = ' ';
	            remain_spaces--;
            }
		}
	}
	while (p - line < max_size)
	{
		*p++ = ' ';
	}
	*p++ = '\0';
}
static char **fullJustify(char **words, int wordsSize, int maxWidth, int *returnSize)
{
	int i, j, k, cap = 100, count = 0;
	char **lines = malloc(cap * sizeof(char *));
	char *buf = malloc(cap * (maxWidth + 1));
	for (i = 0; i < cap; i++)
	{
		lines[i] = buf + i * (maxWidth + 1);
	}
	int *word_lens = malloc(wordsSize * sizeof(int));
	for (i = 0; i < wordsSize; i++)
	{
		word_lens[i] = strlen(words[i]);
	}
	int wc = 0;
	int len = 0;
	int start = 0;
	int chars = 0;
	for (i = 0, j = 0; i < wordsSize; i++)
	{
		if (len + word_lens[i] > maxWidth)
		{
			int even_spaces = wc == 1 ? 0 : (maxWidth - chars) / (wc - 1);
			int remain_spaces = wc == 1 ? 0 : (maxWidth - chars) % (wc - 1);
			line_fill(lines[count], len, words, word_lens, maxWidth, even_spaces, remain_spaces, start, i);
			count++;
			wc = 1;
			len = word_lens[i] + 1;
			chars = word_lens[i];
			start = i;
		}
		else if (len + word_lens[i] == maxWidth)
		{
			chars += word_lens[i];
			int even_spaces = wc == 0 ? 0 : (maxWidth - chars) / wc;
			int remain_spaces = wc == 0 ? 0 : (maxWidth - chars) % wc;
			line_fill(lines[count], len, words, word_lens, maxWidth, even_spaces, remain_spaces, start, i + 1);
			count++;
			wc = 0;
			len = 0;
			chars = 0;
			start = i + 1;
		}
		else
		{
			chars += word_lens[i];
			len += word_lens[i] + 1;
			wc++;
		}
	}
	if (wc > 0)
	{
		char *p = lines[count];
		for (i = start; i < start + wc; i++)
		{
			memcpy(p, words[i], word_lens[i]);
			p += word_lens[i];
			if (i < start + wc - 1)
			{
				*p++ = ' ';
			}
		}
		while (p - lines[count] < maxWidth)
		{
			*p++ = ' ';
		}
		*p++ = '\0';
		count++;
	}
	*returnSize = count;
	return lines;
}
int main(int argc, char **argv)
{
	if (argc <= 2)
	{
		fprintf(stderr, "Usage: ./test maxsize words...\n");
		exit(-1);
	}
	int i, count;
	char **lines = fullJustify(argv + 2, argc - 2, atoi(argv[1]), &count);
	for (i = 0; i < count; i++)
	{
		printf("%s\n", lines[i]);
	}
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值