力扣OJ(0101-200)

目录

101. 对称二叉树

102. 二叉树的层序遍历

103. 二叉树的锯齿形层序遍历

104. 二叉树的最大深度

105. 从前序与中序遍历序列构造二叉树

106. 从中序与后序遍历序列构造二叉树

107. 二叉树的层序遍历 II

108. 将有序数组转换为二叉搜索树

109. 有序链表转换二叉搜索树

110. 平衡二叉树

111. 二叉树的最小深度

112. 路径总和

113. 路径总和 II

116. 填充每个节点的下一个右侧节点指针

117. 填充每个节点的下一个右侧节点指针 II

118. 杨辉三角

119. 杨辉三角 II

121. 买卖股票的最佳时机

122. 买卖股票的最佳时机 II

123. 买卖股票的最佳时机 III

125. 验证回文串

129. 求根到叶子节点数字之和

130. 被围绕的区域

134. 加油站

136. 只出现一次的数字

137. 只出现一次的数字 II

138. 复制带随机指针的链表

139. 单词拆分

140. 单词拆分 II

141. 环形链表

142. 环形链表 II

143. 重排链表

144. 二叉树的前序遍历

145. 二叉树的后序遍历

146. LRU 缓存机制

147. 对链表进行插入排序

148. 排序链表

149. 直线上最多的点数

150. 逆波兰表达式求值

151. 翻转字符串里的单词

152. 乘积最大子序列

153. 寻找旋转排序数组中的最小值

154. 寻找旋转排序数组中的最小值 II

155. 最小栈

156. 上下翻转二叉树

157. 用 Read4 读取 N 个字符

158. 用 Read4 读取 N 个字符 II

159. 至多包含两个不同字符的最长子串

160. 相交链表

161. 相隔为 1 的编辑距离

162. 寻找峰值

163. 缺失的区间

165. 比较版本号

167. 两数之和 II - 输入有序数组

169. 多数元素

170. 两数之和 III - 数据结构设计

172. 阶乘后的零

179. 最大数

186. 翻转字符串里的单词 II

187. 重复的DNA序列

188. 买卖股票的最佳时机 IV

190. 颠倒二进制位

191. 位1的个数

198. 打家劫舍

199. 二叉树的右视图

200. 岛屿数量


101. 对称二叉树

 剑指 Offer 28. 对称的二叉树

102. 二叉树的层序遍历

二叉树BFS

103. 二叉树的锯齿形层序遍历

二叉树BFS

104. 二叉树的最大深度

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

105. 从前序与中序遍历序列构造二叉树

 二叉树

106. 从中序与后序遍历序列构造二叉树

 二叉树

107. 二叉树的层序遍历 II

 二叉树

108. 将有序数组转换为二叉搜索树

 平衡二叉树

109. 有序链表转换二叉搜索树

 平衡二叉树

110. 平衡二叉树

 平衡二叉树

111. 二叉树的最小深度

 二叉树

112. 路径总和

树形DP

113. 路径总和 II

剑指 Offer 34. 二叉树中和为某一值的路径 

116. 填充每个节点的下一个右侧节点指针

是117. 填充每个节点的下一个右侧节点指针 II的退化问题,用一样的代码即可。

117. 填充每个节点的下一个右侧节点指针 II

二叉树BFS

118. 杨辉三角

题目:

给定一个非负整数 numRows,生成杨辉三角的前 numRows 行。

在杨辉三角中,每个数是它左上方和右上方的数的和。

示例:

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

代码:

class Solution {
public:
	vector<vector<int>> generate(int numRows) {
		vector<vector<int>>ans;
		vector<int>line;
		for (int i = 0; i < numRows; i++)
		{
			for (int j = 0; j < i - 1; j++)
			{
				line[j] += line[j + 1];
			}
			line.insert(line.begin(), 1);
			ans.insert(ans.end(), line);
		}
		return ans;
	}
};

119. 杨辉三角 II

题目:

给定一个非负索引 k,其中 k ≤ 33,返回杨辉三角的第 k 行。

在杨辉三角中,每个数是它左上方和右上方的数的和。

示例:

输入: 3
输出: [1,3,3,1]
进阶:

你可以优化你的算法到 O(k) 空间复杂度吗?

代码:

class Solution {
public:
	vector<int> getRow(int rowIndex) {
		vector<int>line;
		for (int i = 0; i <= rowIndex; i++)
		{
			for (int j = 0; j < i - 1; j++)
			{
				line[j] += line[j + 1];
			}
			line.insert(line.begin(), 1);
		}
		return line;
	}
};

121. 买卖股票的最佳时机

 状态转换DP

122. 买卖股票的最佳时机 II

 贪心(4)选取问题

123. 买卖股票的最佳时机 III

 状态转换DP

125. 验证回文串

 双指针

129. 求根到叶子节点数字之和

树形DP

130. 被围绕的区域

 DFS、BFS

134. 加油站

 贪心(4)选取问题

136. 只出现一次的数字

 数组和集合的搜索

137. 只出现一次的数字 II

 数组和集合的搜索

138. 复制带随机指针的链表

 剑指 Offer 35. 复杂链表的复制

139. 单词拆分

字典树

140. 单词拆分 II

字典树

141. 环形链表

 双指针

142. 环形链表 II

双指针

143. 重排链表

144. 二叉树的前序遍历

 二叉树

145. 二叉树的后序遍历

 二叉树

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
 

提示:

1 <= capacity <= 3000
0 <= key <= 3000
0 <= value <= 104
最多调用 3 * 104 次 get 和 put

思路:

维护一个单链表,插入的时候就及时在尾部插入,删除属于懒惰操作,整个的平均时间是O(1),但是单次调用函数的时间不是。

typedef struct Node{
    int key;
    struct Node*next;
}Node;

class LRUCache {
public:
    int N,num;
    Node *head,*tail;
    unordered_map<int,Node*>m;
    unordered_map<int,int>mv;
    LRUCache(int capacity) {
        m.clear();
        mv.clear();
        N=capacity,num=0;
        head=NULL,tail=NULL;
    }

    void fresh(int key)
    {
        Node* p = new Node[1];
        p->key=key;
        p->next=NULL;
        m[key]=p;
        if(head==NULL){
            head=p,tail=p;
        }else{
            tail->next=p,tail=p;
        }
        if(num>N){
            while(m[head->key]!=head)head=head->next;
            m[head->key]=NULL,mv[head->key]=0;
            head=head->next;
            num--;
        }
    }
    
    int get(int key) {
        if(mv[key]){
            fresh(key);
            return mv[key]-1;
        }
        return -1;
    }
    
    void put(int key, int value) {
        if(mv[key]==0)num++;
        mv[key]=value+1;
        fresh(key);
    }
};

或者用双向链表:

typedef struct Node{
    int key;
    struct Node*pre;
    struct Node*next;
}Node;

class LRUCache {
public:
    int N,num;
    Node *head,*tail;
    unordered_map<int,Node*>m;
    unordered_map<int,int>mv;
    LRUCache(int capacity) {
        m.clear();
        mv.clear();
        N=capacity,num=0;
        head=NULL,tail=NULL;
    }

    void fresh(int key)
    {
        Node* p = new Node[1];
        p->key=key;
        p->pre = p->next = NULL;
	    m[key]=p;
        if(head==NULL){
            head=p,tail=p;
        }else{
            tail->next=p,p->pre=tail,tail=p;
        }
        if(num>N){
            while(m[head->key]!=head)head=head->next;
            mv[head->key]=0;
            head=head->next;
            num--;
        }
    }
    
    int get(int key) {
        if(mv[key]){
            fresh(key);
            return mv[key]-1;
        }
        return -1;
    }
    
    void put(int key, int value) {
        if(mv[key]==0)num++;
        mv[key]=value+1;
        fresh(key);
    }
};

147. 对链表进行插入排序

排序算法 排序算法_nameofcsdn的博客-CSDN博客

148. 排序链表

排序算法 排序算法_nameofcsdn的博客-CSDN博客

149. 直线上最多的点数

几何

150. 逆波兰表达式求值

给你一个字符串数组 tokens ,表示一个根据 逆波兰表示法 表示的算术表达式。

请你计算该表达式。返回一个表示表达式值的整数。

注意:

  • 有效的算符为 '+''-''*' 和 '/' 。
  • 每个操作数(运算对象)都可以是一个整数或者另一个表达式。
  • 两个整数之间的除法总是 向零截断 。
  • 表达式中不含除零运算。
  • 输入是一个根据逆波兰表示法表示的算术表达式。
  • 答案及所有中间计算结果可以用 32 位 整数表示。

示例 1:

输入:tokens = ["2","1","+","3","*"]
输出:9
解释:该算式转化为常见的中缀算术表达式为:((2 + 1) * 3) = 9

示例 2:

输入:tokens = ["4","13","5","/","+"]
输出:6
解释:该算式转化为常见的中缀算术表达式为:(4 + (13 / 5)) = 6

示例 3:

输入:tokens = ["10","6","9","3","+","-11","*","/","*","17","+","5","+"]
输出:22
解释:该算式转化为常见的中缀算术表达式为:
  ((10 * (6 / ((9 + 3) * -11))) + 17) + 5
= ((10 * (6 / (12 * -11))) + 17) + 5
= ((10 * (6 / -132)) + 17) + 5
= ((10 * 0) + 17) + 5
= (0 + 17) + 5
= 17 + 5
= 22

提示:

  • 1 <= tokens.length <= 104
  • tokens[i] 是一个算符("+""-""*" 或 "/"),或是在范围 [-200, 200] 内的一个整数

逆波兰表达式:

逆波兰表达式是一种后缀表达式,所谓后缀就是指算符写在后面。

  • 平常使用的算式则是一种中缀表达式,如 ( 1 + 2 ) * ( 3 + 4 ) 。
  • 该算式的逆波兰表达式写法为 ( ( 1 2 + ) ( 3 4 + ) * ) 。

逆波兰表达式主要有以下两个优点:

  • 去掉括号后表达式无歧义,上式即便写成 1 2 + 3 4 + * 也可以依据次序计算出正确结果。
  • 适合用栈操作运算:遇到数字则入栈;遇到算符则取出栈顶两个数字进行计算,并将结果压入栈中
class Solution {
public:
    int evalRPN(vector<string>& tokens) {
        stack<int>st;
        for(auto s:tokens){
            if(s=="+"||s=="-"||s=="*"||s=="/"){
                int b=st.top();
                st.pop();
                int a=st.top();
                st.pop();
                if(s=="+")st.push(a+b);
                if(s=="-")st.push(a-b);
                if(s=="*")st.push(a*b);
                if(s=="/")st.push(a/b);
            }
            else{
                st.push(StrToInt(s.data(),10));
            }
        }
        return st.top();
    }
};

151. 翻转字符串里的单词

 剑指 Offer 58 - I. 翻转单词顺序

152. 乘积最大子序列

DP 数列DP_nameofcsdn的博客-CSDN博客

153. 寻找旋转排序数组中的最小值

二分法 二分、三分_nameofcsdn的博客-CSDN博客

154. 寻找旋转排序数组中的最小值 II

题目:

假设按照升序排序的数组在预先未知的某个点上进行了旋转。

( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。

请找出其中最小的元素。

注意数组中可能存在重复的元素。

示例 1:

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

示例 2:

输入: [2,2,2,0,1]
输出: 0

说明:

分析:

这题没有复杂度优于O(n)的解法

代码:

class Solution {
public:
	int findMin(vector<int>& nums) {
		if (nums.empty())return 0;
		int ans = nums[0];
		for (int i = 0; i < nums.size(); i++)ans = min(ans, nums[i]);
		return ans;
	}
};

155. 最小栈

单调栈

156. 上下翻转二叉树

二叉树 二叉树_nameofcsdn的博客-CSDN博客

157. 用 Read4 读取 N 个字符

给你一个文件,并且该文件只能通过给定的 read4 方法来读取,请实现一个方法使其能够读取 n 个字符。

read4 方法:

API read4 可以从文件中读取 4 个连续的字符,并且将它们写入缓存数组 buf 中。

返回值为实际读取的字符个数。

注意 read4() 自身拥有文件指针,很类似于 C 语言中的 FILE *fp 。

read4 的定义:

参数类型: char[] buf4
返回类型: int

注意: buf4[] 是目标缓存区不是源缓存区,read4 的返回结果将会复制到 buf4[] 当中。
下列是一些使用 read4 的例子:

File file("abcde"); // 文件名为 "abcde", 初始文件指针 (fp) 指向 'a' 
char[] buf4 = new char[4]; // 创建一个缓存区使其能容纳足够的字符
read4(buf4); // read4 返回 4。现在 buf4 = "abcd",fp 指向 'e'
read4(buf4); // read4 返回 1。现在 buf4 = "e",fp 指向文件末尾
read4(buf4); // read4 返回 0。现在 buf = "",fp 指向文件末尾
read 方法:

通过使用 read4 方法,实现 read 方法。该方法可以从文件中读取 n 个字符并将其存储到缓存数组 buf 中。您 不能 直接操作文件。

返回值为实际读取的字符。

read 的定义:

参数类型:   char[] buf, int n
返回类型:   int

注意: buf[] 是目标缓存区不是源缓存区,你需要将结果写入 buf[] 中。
 

示例 1:

输入: file = "abc", n = 4
输出: 3
解释: 当执行你的 read 方法后,buf 需要包含 "abc"。 文件一共 3 个字符,因此返回 3。 注意 "abc" 是文件的内容,不是 buf 的内容,buf 是你需要写入结果的目标缓存区。 
示例 2:

输入: file = "abcde", n = 5
输出: 5
解释: 当执行你的 read 方法后,buf 需要包含 "abcde"。文件共 5 个字符,因此返回 5。
示例 3:

输入: file = "abcdABCD1234", n = 12
输出: 12
解释: 当执行你的 read 方法后,buf 需要包含 "abcdABCD1234"。文件一共 12 个字符,因此返回 12。
示例 4:

输入: file = "leetcode", n = 5
输出: 5
解释: 当执行你的 read 方法后,buf 需要包含 "leetc"。文件中一共 5 个字符,因此返回 5。
 

提示:

你 不能 直接操作该文件,文件只能通过 read4 获取而 不能 通过 read。
read  函数只在每个测试用例调用一次。
你可以假定目标缓存数组 buf 保证有足够的空间存下 n 个字符。 

/**
 * The read4 API is defined in the parent class Reader4.
 *     int read4(char *buf4);
 */

class Solution {
public:
    int read(char *buf, int n) {
        int ans=0,s;
        char* buf4 = new char[4];
        while(n>0 && (s=read4(buf4))>0){
            for(int i=0;i<4 && i<n && i<s;i++)buf[i]=buf4[i],ans++;
            buf+=4,n-=4;
        }
        return ans;
    }
};

158. 用 Read4 读取 N 个字符 II

给你一个文件 file ,并且该文件只能通过给定的 read4 方法来读取,请实现一个方法使其能够使 read 读取 n 个字符。注意:你的 read 方法可能会被调用多次。

read4 的定义:

read4 API 从文件中读取 4 个连续的字符,然后将这些字符写入缓冲区数组 buf4 。

返回值是读取的实际字符数。

请注意,read4() 有其自己的文件指针,类似于 C 中的 FILE * fp 。

    参数类型: char[] buf4
    返回类型: int

注意: buf4[] 是目标缓存区不是源缓存区,read4 的返回结果将会复制到 buf4[] 当中。

下列是一些使用 read4 的例子:

File file("abcde"); // 文件名为 "abcde", 初始文件指针 (fp) 指向 'a' 
char[] buf4 = new char[4]; // 创建一个缓存区使其能容纳足够的字符
read4(buf4); // read4 返回 4。现在 buf4 = "abcd",fp 指向 'e'
read4(buf4); // read4 返回 1。现在 buf4 = "e",fp 指向文件末尾
read4(buf4); // read4 返回 0。现在 buf4 = "",fp 指向文件末尾

read 方法:

通过使用 read4 方法,实现 read 方法。该方法可以从文件中读取 n 个字符并将其存储到缓存数组 buf 中。您 不能 直接操作 file 。

返回值为实际读取的字符。

read 的定义:

    参数类型:  char[] buf, int n
    返回类型:  int

注意: buf[] 是目标缓存区不是源缓存区,你需要将结果写入 buf[] 中。

注意:

  • 你 不能 直接操作该文件,文件只能通过 read4 获取而 不能 通过 read
  • read  函数可以被调用 多次
  • 请记得 重置 在 Solution 中声明的类变量(静态变量),因为类变量会 在多个测试用例中保持不变,影响判题准确。请 查阅 这里。
  • 你可以假定目标缓存数组 buf 保证有足够的空间存下 n 个字符。 
  • 保证在一个给定测试用例中,read 函数使用的是同一个 buf

示例 1:

输入: file = "abc", queries = [1,2,1]
输出:[1,2,0]
解释:测试用例表示以下场景:
File file("abc");
Solution sol;
sol.read (buf, 1); // 调用 read 方法后,buf 应该包含 “a”。我们从文件中总共读取了 1 个字符,所以返回 1。
sol.read (buf, 2); // 现在 buf 应该包含 "bc"。我们从文件中总共读取了 2 个字符,所以返回 2。
sol.read (buf, 1); // 我们已经到达文件的末尾,不能读取更多的字符。所以返回 0。
假设已经分配了 buf ,并保证有足够的空间存储文件中的所有字符。

示例 2:

输入:file = "abc", queries = [4,1]
输出:[3,0]
解释:测试用例表示以下场景:
File file("abc");
Solution sol;
sol.read (buf, 4); // 调用 read 方法后,buf 应该包含 “abc”。我们从文件中总共读取了 3 个字符,所以返回 3。
sol.read (buf, 1); // 我们已经到达文件的末尾,不能读取更多的字符。所以返回 0。

提示:

  • 1 <= file.length <= 500
  • file 由英语字母和数字组成
  • 1 <= queries.length <= 10
  • 1 <= queries[i] <= 500

思路:

首先理解接口形式,这里应该是把Solution的定义放到了一个更大的类里面,这个更大的类有read4这个方法,他们的关系的嵌套,而不是继承。

其中主要就是理解题意了。

/**
 * The read4 API is defined in the parent class Reader4.
 *     int read4(char *buf4);
 */

class Solution {
public:
    /**
     * @param buf Destination buffer
     * @param n   Number of characters to read
     * @return    The number of actual characters read
     */
    int readbuf()
    {
        if(num)return num;
        return num=read4(buf);
    }
    void delbuf(int n)
    {
        for(int i=n;i<4;i++)buf[i-n]=buf[i];
        num-=n;
    }
    int read(char *buf, int n) {
        int ans=0;
        while(n){
            int len=readbuf();
            if(!len)return ans;
            len=min(n,num);
            memcpy(buf+ans,this->buf,len);
            n-=len,ans+=len;
            delbuf(len);
        }
        return ans;
    }
    char buf[4];
    int num=0;
};

159. 至多包含两个不同字符的最长子串

给你一个字符串 s ,请你找出 至多 包含 两个不同字符 的最长子串,并返回该子串的长度。

示例 1:

输入:s = "eceba"
输出:3
解释:满足题目要求的子串是 "ece" ,长度为 3 。

示例 2:

输入:s = "ccaabbb"
输出:5
解释:满足题目要求的子串是 "aabbb" ,长度为 5 。

提示:

  • 1 <= s.length <= 105
  • s 由英文字母组成
class Solution {
public:
	int lengthOfLongestSubstringTwoDistinct(string s) {
		return lengthOfLongestSubstringTwoDistinct(s, 2);
	}
	int lengthOfLongestSubstringTwoDistinct(const string s, int k) {
		int n = s.size();
		if (n * k == 0) return 0;

		int left = 0, right = 0;
		int max_len = 1;
		unordered_map<char, int> hashmap;

		while (right < n) {
			hashmap[s[right]] = right;
			right++;

			if (hashmap.size() == k + 1) {
				int del_idx = INT_MAX;
				for (auto& p : hashmap) {
					del_idx = min(del_idx, p.second);
				}
				hashmap.erase(s[del_idx]);
				left = del_idx + 1;
			}

			max_len = max(max_len, right - left);
		}

		return max_len;
	}
};

160. 相交链表

剑指 Offer 52. 两个链表的第一个公共节点 

161. 相隔为 1 的编辑距离

双指针 双指针、多指针_nameofcsdn的博客-CSDN博客

162. 寻找峰值

二分法

163. 缺失的区间

给定一个排序的整数数组 nums ,其中元素的范围在 闭区间 [lower, upper] 当中,返回不包含在数组中的缺失区间。

示例:

输入: nums = [0, 1, 3, 50, 75], lower = 0 和 upper = 99,
输出: ["2", "4->49", "51->74", "76->99"]

class Solution {
public:
	vector<string> findMissingRanges(vector<int>& nums, int lower, int upper) {
		nums.push_back(++upper);
		sort(nums.begin(), nums.end());
		int a = lower, b = lower;
		vector<string>ans;
		for (int i = 0; i < nums.size(); i++)
		{
			b = nums[i] - 1;
			char* sa = new char[20];
			IntToStr(a, 10, sa);
			char* sb = new char[20];
			IntToStr(b, 10, sb);
			if (a < b)ans.push_back(string(sa) + "->" + string(sb));
			else if (a == b)ans.push_back(string(sa));
			a = nums[i] + 1;
		}
		return ans;
	}
};

165. 比较版本号

给你两个版本号 version1 和 version2 ,请你比较它们。

版本号由一个或多个修订号组成,各修订号由一个 '.' 连接。每个修订号由 多位数字 组成,可能包含 前导零 。每个版本号至少包含一个字符。修订号从左到右编号,下标从 0 开始,最左边的修订号下标为 0 ,下一个修订号下标为 1 ,以此类推。例如,2.5.33 和 0.1 都是有效的版本号。

比较版本号时,请按从左到右的顺序依次比较它们的修订号。比较修订号时,只需比较 忽略任何前导零后的整数值 。也就是说,修订号 1 和修订号 001 相等 。如果版本号没有指定某个下标处的修订号,则该修订号视为 0 。例如,版本 1.0 小于版本 1.1 ,因为它们下标为 0 的修订号相同,而下标为 1 的修订号分别为 0 和 1 ,0 < 1 。

返回规则如下:

  • 如果 version1 version2 返回 1
  • 如果 version1 version2 返回 -1
  • 除此之外返回 0

示例 1:

输入:version1 = "1.01", version2 = "1.001"
输出:0
解释:忽略前导零,"01" 和 "001" 都表示相同的整数 "1"

示例 2:

输入:version1 = "1.0", version2 = "1.0.0"
输出:0
解释:version1 没有指定下标为 2 的修订号,即视为 "0"

示例 3:

输入:version1 = "0.1", version2 = "1.1"
输出:-1
解释:version1 中下标为 0 的修订号是 "0",version2 中下标为 0 的修订号是 "1" 。0 < 1,所以 version1 < version2

提示:

  • 1 <= version1.length, version2.length <= 500
  • version1 和 version2 仅包含数字和 '.'
  • version1 和 version2 都是 有效版本号
  • version1 和 version2 的所有修订号都可以存储在 32 位整数 中
class Solution {
public:
	int compareVersion(string version1, string version2) {
		map<char, int>m;
		m['.'] = 1;
		vector<string>v1 = StringOpt::stringSplit(version1, m);
		vector<string>v2 = StringOpt::stringSplit(version2, m);
		int len = max(v1.size(), v2.size());
		for (int i = 0; i < len; i++) {
			int x1 = 0, x2 = 0;
			if (i < v1.size())x1 = StrToInt(v1[i].data(), 10);
			if (i < v2.size())x2 = StrToInt(v2[i].data(), 10);
			if (x1 < x2)return -1;
			if (x1 > x2)return 1;
		}
		return 0;
	}
};

167. 两数之和 II - 输入有序数组

数组和集合的搜索 数组和集合的搜索_nameofcsdn的博客-CSDN博客

169. 多数元素

剑指 Offer 39. 数组中出现次数超过一半的数字 

170. 两数之和 III - 数据结构设计

设计一个接收整数流的数据结构,该数据结构支持检查是否存在两数之和等于特定值。

实现 TwoSum 类:

  • TwoSum() 使用空数组初始化 TwoSum 对象
  • void add(int number) 向数据结构添加一个数 number
  • boolean find(int value) 寻找数据结构中是否存在一对整数,使得两数之和与给定的值相等。如果存在,返回 true ;否则,返回 false 。

示例:

输入:
["TwoSum", "add", "add", "add", "find", "find"]
[[], [1], [3], [5], [4], [7]]
输出:
[null, null, null, null, true, false]

解释:
TwoSum twoSum = new TwoSum();
twoSum.add(1);   // [] --> [1]
twoSum.add(3);   // [1] --> [1,3]
twoSum.add(5);   // [1,3] --> [1,3,5]
twoSum.find(4);  // 1 + 3 = 4,返回 true
twoSum.find(7);  // 没有两个整数加起来等于 7 ,返回 false

提示:

  • -105 <= number <= 105
  • -231 <= value <= 231 - 1
  • 最多调用 104 次 add 和 find
class TwoSum {
public:
    void add(int number) {
        m[number]++;
    }
    
    bool find(long long value) {
        for(auto p:m){
            int x=value-p.first;
            auto it = m.find(x);
            if(it==m.end())continue;
            if(x!=p.first)return true;
            else if(it->second>1)return true;
        }
        return false;
    }
    map<int,int>m;
};

172. 阶乘后的零

阶乘

179. 最大数

rust

186. 翻转字符串里的单词 II

调用151. 翻转字符串里的单词里面的函数

class Solution {
public:
	string reverseWords(string s) {
		vector<string>v = StringSplit(s);
		return StringJoin(Frev(v),' ');
	}
	void reverseWords(vector<char>& s) {
		s.push_back('\0');
		string str = reverseWords(CharToString(s));
		s = StringToCharVec(str);
	}
};

187. 重复的DNA序列

水题

188. 买卖股票的最佳时机 IV

状态转换DP

189. 轮转数组

给定一个整数数组 nums,将数组中的元素向右轮转 k 个位置,其中 k 是非负数。

示例 1:

输入: nums = [1,2,3,4,5,6,7], k = 3
输出: [5,6,7,1,2,3,4]
解释:
向右轮转 1 步: [7,1,2,3,4,5,6]
向右轮转 2 步: [6,7,1,2,3,4,5]
向右轮转 3 步: [5,6,7,1,2,3,4]

示例 2:

输入:nums = [-1,-100,3,99], k = 2
输出:[3,99,-1,-100]
解释: 
向右轮转 1 步: [99,-1,-100,3]
向右轮转 2 步: [3,99,-1,-100]

提示:

  • 1 <= nums.length <= 105
  • -231 <= nums[i] <= 231 - 1
  • 0 <= k <= 105

进阶:

  • 尽可能想出更多的解决方案,至少有 三种 不同的方法可以解决这个问题。
  • 你可以使用空间复杂度为 O(1) 的 原地 算法解决这个问题吗?
class Solution {
public:
    void rotate(vector<int>& nums, int k) {
        rotate(nums,0,nums.size(),k%nums.size());
    }
    void rotate(vector<int>& nums, int low, int n, int k) {
        if(k==0||k==n)return;
        if(k>n-k){
            change(nums,low,low+k,n-k);
            rotate(nums,low,k,k*2-n);
        }else{
            change(nums,low,low+n-k,k);
            rotate(nums,low+k,n-k,k);
        }
    }
    void change(vector<int>& nums, int id1,int id2,int len){
        for(int i=0;i<len;i++)swap(nums[id1+i],nums[id2+i]);
    }
};

190. 颠倒二进制位

位运算

191. 位1的个数

位运算

198. 打家劫舍

数列DP

199. 二叉树的右视图

二叉树

200. 岛屿数量

并查集

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值