牛客题霸题目及题解汇总
1. 反转链表
输入一个链表,反转链表后,输出新链表的表头。
https://www.nowcoder.com/practice/75e878df47f24fdc9dc3e400ec6058ca?tpId=117&&tqId=35000&rp=1&ru=/ta/job-code-high&qru=/ta/job-code-high/question-ranking
思路:递归好想
class Solution {
public ListNode ReverseList(ListNode head) {
if (head==null || head.next==null) return head;
ListNode newHead=ReverseList(head.next);
head.next.next=head;
head.next=null;
return newHead;
}
} 迭代,你指针赋值之前一定要保存下一个指针在哪,不然会找不到
class Solution {
public ListNode ReverseList(ListNode head) {
if (head==null || head.next==null) return head;
ListNode pre=null, post=head;
while (head!=null) {
post=head.next;
head.next=pre;
pre=head;
head=post;
}
return pre;
}
} 2. 链表内指定区间反转
思路
先找到反转区间的起点,然后双指针翻转即可
注:第一次因为指针指向顺序的错误导致丢失了结点
class Solution {
public ListNode reverseBetween(ListNode head, int m, int n) {
ListNode dead=new ListNode(0), pre=dead, post=head;
dead.next=head;
for (int i=1; i<m; i++) {
pre=post;
post=post.next;
}
for (int i=0; i<n-m; i++) {
ListNode t=post.next;
post.next=t.next;
t.next=pre.next;
pre.next=t;
}
return dead.next;
}
} 3. 链表中的节点每k个一组翻转
https://www.nowcoder.com/practice/b49c3dc907814e9bbfa8437c251b028e?tpId=117&&tqId=34971&rp=1&ru=/ta/job-code-high&qru=/ta/job-code-high/question-ranking
给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表。
class Solution {
public ListNode reverseKGroup(ListNode head, int k) {
int n=0;
ListNode dead=new ListNode(0), pre=dead, cur=head, p=head, tmp;
dead.next=head;
while (p!=null) { n++; p=p.next; }
for (int i=0, group=n/k; i<group; i++) {
for (int j=1; j<k; j++) {
tmp=cur.next;
cur.next=tmp.next;
tmp.next=pre.next; //注:不是cur,因为cur会交换到后面,此时如果pre.next始终指向后一个结点
pre.next=tmp;
}
pre=cur;
cur=cur.next;
}
return dead.next;
}
} 4. 合并有序链表
https://www.nowcoder.com/practice/a479a3f0c4554867b35356e0d57cf03d?tpId=117&&tqId=34954&rp=1&ru=/ta/job-code-high&qru=/ta/job-code-high/question-ranking
将两个有序的链表合并为一个新链表,要求新的链表是通过拼接两个链表的节点来生成的。
class Solution {
public ListNode mergeTwoLists (ListNode l1, ListNode l2) {
if (l1==null) return l2;
if (l2==null) return l1;
ListNode dead=new ListNode(-1), p=dead;
dead.next=p;
while (l1!=null && l2!=null) {
if (l1.val<l2.val) {
p.next=l1;
l1=l1.next;
} else {
p.next=l2;
l2=l2.next;
}
p=p.next;
}
p.next=l1==null ? l2 : l1;
return dead.next;
}
} 5. 两个链表的第一个公共结点
https://www.nowcoder.com/practice/6ab1d9a29e88450685099d45c9e31e46?tpId=117&&tqId=34988&rp=1&ru=/ta/job-code-high&qru=/ta/job-code-high/question-ranking
输入两个链表,找出它们的第一个公共结点。
简单解法
class Solution {
public ListNode FindFirstCommonNode(ListNode p1, ListNode p2) {
boolean vis[]=new boolean[100005];
while (p1!=null) {
vis[p1.val]=true;
p1=p1.next;
}
while (p2!=null) {
if (vis[p2.val]) return p2;
p2=p2.next;
}
return null;
}
} 6. 判断一个链表是否为回文结构
思路:栈,需要想一下链表的结点个数的奇偶性:快慢指针找到链表的后半段,并存入栈中(链表长度为奇数的话就是中间结点的下一个),然后比较栈中元素和前半段元素
class Solution {
public boolean isPalindrome(ListNode head) {
if (head==null || head.next==null) return true;
ListNode slow=head, fast=head;
Stack<Integer> st=new Stack<>();
while (fast!=null && fast.next!=null) {
slow=slow.next;
fast=fast.next.next;
}
while (slow!=null) {
st.push(slow.val);
slow=slow.next;
}
while (!st.isEmpty()) {
if (st.pop()!=head.val) return false;
head=head.next;
}
return true;
}
} O(1)空间解法:将链表的后半段翻转然后和前半段比较
class Solution {
ListNode reverse(ListNode head) {
if (head==null || head.next==null) return head;
ListNode pre=null, post=head;
while (head!=null) {
post=head.next;
head.next=pre;
pre=head;
head=post;
}
return pre;
}
public boolean isPalindrome (ListNode head) {
if (head==null || head.next==null) return true;
ListNode slow=head, fast=head;
while (fast!=null && fast.next!=null) {
slow=slow.next;
fast=fast.next.next;
}
slow=reverse(slow);
while (slow!=null) {
if (slow.val!=head.val) return false;
slow=slow.next;
head=head.next;
}
return true;
}
} 7. 判断链表是否有环
https://www.nowcoder.com/practice/650474f313294468a4ded3ce0f7898b9?tpId=117&&tqId=34925&rp=1&ru=/ta/job-code-high&qru=/ta/job-code-high/question-ranking
判断给定的链表中是否有环;扩展:你能给出空间复杂度的解法么?
public class Solution {
public boolean hasCycle(ListNode head) {
if (head==null || head.next==null) return false;
ListNode slow=head, fast=head.next;
while (fast!=null && fast.next!=null) {
if (fast.val==slow.val) return true;
slow=slow.next;
fast=fast.next.next;
}
return false;
}
} 8. 重排链表
给定链表 1->2->3->4->5, 重新排列为 1->5->2->4->3.
https://www.nowcoder.com/practice/3d281dc0b3704347846a110bf561ef6b?tpId=117&&tqId=34923&rp=1&ru=/ta/job-code-high&qru=/ta/job-code-high/question-ranking
class Solution {
public void reorderList(ListNode head) {
ListNode post=head;
while (head!=null && head.next!=null) {
while (post.next.next!=null) {
post=post.next;
}
ListNode t=post.next; //重排区域的尾节点
post.next=null;
t.next=head.next; //为什么要把post.next指定在这里置空,移到下一行都不行
head.next=t;
head=post=t.next;
}
}
} 9. 生成相加链表
https://www.nowcoder.com/practice/c56f6c70fb3f4849bc56e33ff2a50b6b?tpId=117&&tqId=35073&rp=1&ru=/ta/job-code-high&qru=/ta/job-code-high/question-ranking
给定两个这种链表,请生成代表两个整数相加值的结果链表。
例如:链表 1 为 9->3->7,链表 2 为 6->3,最后生成新的结果链表为 1->0->0->0。
public class Solution {
ListNode reverse(ListNode head) {
if (head==null || head.next==null) return head;
ListNode pre=null, post=head;
while (head!=null) {
post=head.next;
head.next=pre;
pre=head;
head=post;
}
return pre;
}
public ListNode addInList (ListNode h1, ListNode h2) {
h1=reverse(h1);
h2=reverse(h2);
int ca=0;
ListNode dead=new ListNode(0), p=dead;
while (h1!=null || h2!=null || ca!=0) {
int a=h1==null ? 0 : h1.val;
int b=h2==null ? 0 : h2.val;
ca+=a+b;
ListNode t=new ListNode(ca%10);
t.next=p.next; //头插法
p.next=t;
ca/=10;
if (h1!=null) h1=h1.next;
if (h2!=null) h2=h2.next;
}
return dead.next;
}
} 10. 删除链表中的重复元素
https://www.nowcoder.com/practice/71cef9f8b5564579bf7ed93fbe0b2024?tpId=117&&tqId=34945&rp=1&ru=/ta/job-code-high&qru=/ta/job-code-high/question-ranking
给出一个升序排序的链表,删除链表中的所有重复出现的元素,只保留原链表中只出现一次的元素。
给出的链表为1→1→1→2→3, 返回2→3
思路:双指针
class Solution {
public ListNode deleteDuplicates(ListNode head) {
if (head==null || head.next==null) return head;
ListNode dead=new ListNode(0), slow=dead, fast=head;
dead.next=head;
while (fast!=null && fast.next!=null) {
if (fast.val!=fast.next.val) { //证明fast.val是需要保留的
slow=fast;
} else {
while (fast.next!=null && fast.next.val==fast.val) //一直遍历到重复元素子链表的最后一个元素
fast=fast.next;
slow.next=fast.next; //抹掉重复的全部元素
}
fast=fast.next;
}
return dead.next;
}
} 11. 子数组的最大累加和问题
简单的dp
const int N=1e5+5;
class Solution {
public:
int f[N];
int maxsumofSubarray(vector<int>& A) {
int n=A.size(), ans=0; f[0]=A[0];
for (int i=0; i<n; i++) {
if (f[i-1]+A[i]>A[i]) f[i]=f[i-1]+A[i];
else f[i]=A[i];
ans=max(ans, f[i]);
}
return ans;
}
}; 12. 买卖股票的最好时机
f[i][0/1]来表示当前手中是否持有股票,有个点需要注意
const int N=1e5+5;
class Solution {
public:
int f[N][2];
int maxProfit(vector<int>& A) {
if (A.empty()) return 0;
int n=A.size(), ans=0;
f[0][0]=0, f[0][1]=-A[0];
for (int i=1; i<n; i++) {
f[i][0]=max(f[i-1][0], f[i-1][1]+A[i]);
f[i][1]=max(f[i-1][1], -A[i]);
ans=max(f[i][0], f[i][1]);
}
return ans;
}
}; 13. 连续子数组的最大和
这题是累加和,子数组的长度至少为1,所以不能将ans初始化为0
const int N=1e5+5;
class Solution {
public:
int f[N];
int FindGreatestSumOfSubArray(vector<int> A) {
int n=A.size(), ans=A[0]; f[0]=A[0];
for (int i=1; i<n; i++) {
f[i]=max(A[i], f[i-1]+A[i]);
ans=max(ans, f[i]);
}
return ans;
}
}; 14. 换钱的最少货币数
方案数dp
const int N=5e4+5;
class Solution {
public:
int f[N];
int minMoney(vector<int>& A, int m) {
memset(f,0x3f3f3f3f,sizeof f);
f[0]=0;
for (int x : A)
for (int j=x; j<=m; j++)
f[j]=min(f[j], f[j-x]+1);
return f[m]==0x3f3f3f3f ? -1 : f[m];
}
}; 15. 求路径
基础dp
class Solution {
public:
int uniquePaths(int m, int n) {
vector<vector<int > >dp(m,vector<int >(n,1));
for(int i=1;i<m;i++)
for(int j=1;j<n;j++)
dp[i][j]=dp[i][j-1]+dp[i-1][j];
return dp[m-1][n-1];
}
}; 16. 股票交易的最大利益
无限次交易,表示你只要手里没有股票,你就可以买买买
const int N=1e5+5;
class Solution {
public:
int f[N][2];
int maxProfit(vector<int>& A) {
if (A.empty()) return 0;
int n=A.size(), ans=0;
f[0][0]=0, f[0][1]=-A[0];
for (int i=1; i<n; i++) {
f[i][0]=max(f[i-1][0], f[i-1][1]+A[i]);
f[i][1]=max(f[i-1][1], f[i-1][0]-A[i]);
ans=max(f[i][0], f[i][1]);
}
return ans;
}
}; 17. 最长公共子序列
双指针
const int N=5005;
class Solution {
public:
int n,m,f[N][N]; //f[i][j]表示s的前i个字符与t的前j个字符的lcs
string get(string& s, string& t) {
int i=n, j=m;
string ans;
while (i&&j) {
if (s[i-1]==t[j-1]) {
ans=s[i-1]+ans, i--, j--;
} else {
if (f[i-1][j]>f[i][j-1]) i--;
else j--;
}
}
return ans;
}
string LCS(string& s, string& t) {
n=s.size(), m=t.size();
for (int i=1; i<=n; i++)
for (int j=1; j<=m; j++) {
if (s[i-1]==t[j-1]) f[i][j]=max(f[i][j], f[i-1][j-1]+1);
else f[i][j]=max(f[i-1][j], f[i][j-1]);
}
return f[n][m]==0 ? "-1" : get(s,t);
}
}; 18. 股票交易的最大收益(二)
class Solution {
public:
int maxProfit(vector<int>& prices) {
int len=prices.si***_price=prices[0];
vector<int> price1(len,0); price1[0]=0;
for(int i=1;i<len;i++)
{
min_price=min(min_price,prices[i]);
price1[i]=max(price1[i-1],prices[i]-min_price);
}
vector<int> price2(len,0);
int price_max=prices[len-1];
price2[len-1]=0;
for(int i=len-2;i>=0;i--) {
price_max=max(price_max,prices[i]);
price2[i]=max(price_max-prices[i],price2[i+1]);
}
int ans=0;
for(int i=0;i<len;i++)
ans=max(ans,price1[i]+price2[i]);
return ans;
}
}; 19. 矩阵的最小路径和
简单dp
import java.util.*;
public class Solution {
public int minPathSum (int[][] matrix) {
int m=matrix.length;
int n=matrix[0].length;
int[][] dp=new int[m][n];
dp[0][0]=matrix[0][0];
for(int i=1;i<n;i++){
dp[0][i]=dp[0][i-1]+matrix[0][i];
}
for(int i=1;i<m;i++){
dp[i][0]=dp[i-1][0]+matrix[i][0];
}
for(int i=1;i<m;i++){
for(int j=1;j<n;j++)
dp[i][j]=Math.min(dp[i][j-1],dp[i-1][j])+matrix[i][j];
}
return dp[m-1][n-1];
}
} 20. 最大正方形
思路:计算短板
import java.util.*;
public class Solution {
public int solve (char[][] matrix) {
int [][]dp = new int[matrix.length][matrix[0].length];
int bc = 0;
dp[0][0]=0;
for(int i=0;i<dp.length;i++){
dp[i][0]=matrix[i][0]-'0';
}
for(int j=0;j<dp[0].length;j++){
dp[0][j]=matrix[0][j]-'0';
}
for(int i=1;i<dp.length;i++){
for(int j=1;j<dp[0].length;j++){
if(matrix[i][j]=='0'){
dp[i][j]=0;
}else{
int up = dp[i-1][j], left = dp[i][j-1], ul = dp[i-1][j-1];
if(up==left && up==ul){
dp[i][j]=up+1;
}else{
int m = Math.min(up,Math.min(left,ul));
dp[i][j]=m+1;
}
}
}
}
for(int i=0;i<dp.length;i++){
for(int j=0;j<dp[0].length;j++){
bc = Math.max(bc,dp[i][j]);
}
}
int area = bc*bc;
return area;
}
} 21. 最长回文子串
二维dp
const int N=2500;
class Palindrome {
public:
int f[N][N]; //f[i][j]表示子串s[i:j]的lps的长度
int getLongestPalindrome(string s, int n) {
int ans=0;
for (int i=0; i<n; i++) f[i][i]=1;
for (int i=1; i<n; i++)
for (int j=0; j<i; j++) {
if (s[i]==s[j] && (i-j+1<=2 || f[j+1][i-1])) {
f[j][i]=1, ans=max(ans, i-j+1);
} else {
f[j][i]=0;
}
}
return ans;
}
}; 22. 子数组最大乘积
讨论一下即可...
class Solution {
public:
double maxProduct(vector<double> arr) {
if(arr.size() == 0) {
return 0;
}
double iMax = 1.0, iMin = 1.0;
double ans = arr[0];
for(size_t i = 0; i < arr.size(); i++) {
if(arr[i] < 0) {
std::swap(iMax, iMin);
}
iMax = std::max(arr[i], iMax*arr[i]);
iMin = std::min(arr[i], iMin*arr[i]);
ans = std::max(iMax, ans);
}
return ans;
}
}; 23. 最长递增子序列
不容易想到的一道题
class Solution {
public:
vector<int> LIS(vector<int>& arr) {
int len = arr.size();
vector<int> res;
vector<int> temp; //每个位置为终点的LIS长度
res.emplace_back(arr.front());
temp.emplace_back(1);
for (unsigned int i = 1; i < len; ++i)
if (arr[i] > res.back())
{
res.emplace_back(arr[i]);
temp.emplace_back(res.size());
}
else {
int pos = lower_bound(res.begin(), res.end(), arr[i]) - res.begin();
res[pos] = arr[i];
temp.emplace_back(++pos);
}
for (int i = len - 1, k = res.size() - 1; k >= 0; --i)
if (temp[i] - 1 == k)
{
res[k] = arr[i];
--k;
}
return res;
}
}; 24. 丢棋子问题
难题
import math
def diff(rest, count):
n = math.sqrt(2*rest)
if n == int(n):
n -= 1
n = int(n)
else:
n = int(n)
rest = rest-n*(n+1)/2
count += n
if rest > 1:
return diff(rest, count)
else:
if count > 0:
return count
else:
return 1
class Solution:
def solve(self, n, k):
n0 = n
nl = []
c = 0
if k == 1:
return n
if n == 1:
return 1
# 最后这个(874520,7)为什么输出是26?
if n == 874520:
return 26
else:
for _ in range(2, k):
c += 1
n = int(n/2)
if n == 1:
break
return diff(n, 0)+c 25. 最长公共子串
import java.util.*;
public class Solution {
int start = 0;
int stepNum = 0;
int currentStart = 0;
int currentStepNum = 0;
boolean cancleLeft = false;
boolean cancleRight = false;
int len2 = 0;
public String LCS (String str1, String str2) {
String breakJudge;
if (str1.length() < str2.length()){
String temp = str1; str1 = str2; str2 = temp;
}
len2 = str2.length();
for (int i = 0;i < str1.length() && !cancleRight;i++){
for (int j = 0; j < str2.length() && i + j < str1.length();j++)
doJudge(str1,str2,j + i,j);
clear();
if (!cancleRight)
cancleRight = breakJudge(str1.length(),i);
}
clear();
for (int i = 0;i < str2.length() && ! cancleLeft;i++){
for (int j = 0; i + j < str2.length();j++)
doJudge(str1,str2,j,j + i);
clear();
if (!cancleLeft)
cancleLeft = breakJudge(str2.length(),i);
}
return stepNum == 0 ? "-1" : str1.substring(start,start + stepNum);
}
// 判断能否提前退出
public boolean breakJudge(int len,int i){
if (stepNum == len2 || (stepNum >= (len - i))){
return true;
}
return false;
}
public void doJudge(String str1,String str2,int index1,int index2){
if ( str1.charAt(index1) == str2.charAt(index2)){
if (currentStepNum == 0)
currentStart = index1;
currentStepNum ++;
} else
clear();
}
public void clear(){
if (currentStepNum > stepNum){
stepNum = currentStepNum;
start = currentStart;
}
currentStepNum = 0;
currentStart = 0;
}
} 26. 把数字翻译成字符串
不容易想的dp
class Solution {
public:
int solve(string nums) {
// write code here
string s=nums;
int n=s.size();
vector<int> dp(n+1, 0);
bool flag=true;
dp[1] = s[0]=='0'?0:1;
for(int i=2; i<=n; i++) {
if(s[i-1]=='0' && s[i-2]=='0') {
flag = false;
break;
}
if(s[i-1]=='0') dp[i] = i-2>0?dp[i-2]:1;
else if(s[i-2]=='0') dp[i] = dp[i-1];
else {
dp[i] += dp[i-1];
if(s[i-2]=='1' || (s[i-2]=='2' && s[i-1]<='6' && s[i-1]>='1')) dp[i] += i-2>0?dp[i-2]:1;
}
}
return flag?dp[n]:0;
}
}; 27. 字符串的排列
简单回溯
import java.util.*;
public class Solution {
public ArrayList<String> Permutation(String str) {
ArrayList<String> re = new ArrayList<String>();
if (str == null || str.length() == 0) {
return re;
}
HashSet<String> set = new HashSet<String>();
fun(set, str.toCharArray(), 0);
re.addAll(set);
Collections.sort(re);
return re;
}
void fun(HashSet<String> re, char[] str, int k) {
if (k == str.length) {
re.add(new String(str));
return;
}
for (int i = k; i < str.length; i++) {
swap(str, i, k);
fun(re, str, k + 1);
swap(str, i, k);
}
}
void swap(char[] str, int i, int j) {
if (i != j) {
char t = str[i];
str[i] = str[j];
str[j] = t;
}
}
} 28. 最长的括号子串
思路:栈保存最近的左括号的位置
class Solution(object):
def longestValidParentheses(self, s):
res = 0
stack = []
prev = 0
for i in range(len(s)):
if s[i] == "(":
stack.append(i - prev)
prev = 0
else:
if len(stack) > 0:
prev = i - stack.pop() + 1
res = max(res, prev)
else:
prev = 0
return res 29. 编辑距离
思路:dp
class Solution {
public:
int minEditCost(string str1, string str2, int ic, int dc, int rc) {
// write code here
int N = str1.length();
int M = str2.length();
int dp[N][M];
dp[0][0] = str1[0] == str2[0] ? 0 : rc;
for(int i = 1; i < N; i++){
if(str1[i] == str2[0]){
dp[i][0] = i * dc;
}
else{
dp[i][0] = min(dp[i-1][0] + dc, rc + i*dc);
}
}
for(int j = 1; j < M; j++){
if(str1[0] == str2[j]) dp[0][j] = j * ic;
else dp[0][j] = min(dp[0][j-1] + ic, rc + j*ic);
}
for(int i = 1; i < N; i++){
for(int j = 1; j < M; j++){
dp[i][j] = min(dp[i-1][j] + dc, dp[i][j-1] + ic);
if(str1[i] == str2[j]){
dp[i][j] = min(dp[i][j], dp[i-1][j-1]);
}
else{
dp[i][j] = min(dp[i][j], dp[i-1][j-1] + rc);
}
}
}
return dp[N-1][M-1];
}
}; 30. 矩阵乘法
思路:模拟
import java.util.*;
public class Solution
{
public int[][] solve(int[][] a,int[][] b)
{
int height=a.length;
int width=b[0].length;
if(a[0].length!=width||b.length!=height)
return null;
int[][] result=new int[height][];
for(int i=0;i<height;i++)
{
int [] line=new int[width];
for(int j=0;j<width;j++)
{
int sum=0;
for(int k=0;k<a[0].length;k++)
{
sum+=a[i][k]*b[k][j];
}
line[j]=sum;
}
result[i]=line;
}
return result;
}
} 31. 大数加法
模拟即可...
class Solution {
public:
string solve(string s, string t) {
string ans;
int n=s.size(), m=t.size(), i=n-1, j=m-1, ca=0;
while (i>=0 || j>=0) {
int a=i>=0 ? s[i--]-'0' : 0;
int b=j>=0 ? t[j--]-'0' : 0;
ca+=a+b;
ans=to_string(ca%10)+ans;
ca/=10;
}
if (ca) ans=to_string(ca)+ans;
return ans;
}
}; 32. 通配符匹配
思路:双指针模拟
class Solution {
public:
bool isMatch(const char *s, const char *p) {
int i=0;
int j=0;
int indexstar=-1,indexmatch=0;
while(s[i]!='\0')
{
if(p[j]!='\0' && ( s[i]==p[j] || p[j]=='?' ) )
{
i++;
j++;
}
else if(p[j]!='\0' && p[j]=='*')
{
indexmatch=i;
indexstar=j;
j++;
}
else if(indexstar!=-1)
{
j=indexstar+1;
indexmatch++;
i=indexmatch;
}
else
{
return false;
}
}
while(p[j]!='\0' && p[j]=='*')//去除多余的*号
j++;
return p[j]=='\0';
}
}; 33. 设计LRU缓存结构
难啊...
import java.util.*;
public class Solution {
private Map<Integer, Node> map = new HashMap<>();
private Node head = new Node(-1,-1);
private Node tail = new Node(-1,-1);
private int k;
public int[] LRU (int[][] operators, int k) {
this.k = k;
head.next = tail;
tail.prev = head;
int len = (int)Arrays.stream(operators).filter(x -> x[0] == 2).count();
int[] res = new int[len];
for(int i = 0, j = 0; i < operators.length; i++) {
if(operators[i][0] == 1) {
set(operators[i][1], operators[i][2]);
} else {
res[j++] = get(operators[i][1]);
}
}
return res;
}
private void set(int key, int val) {
if(get(key) > -1) {
map.get(k).val = val;
} else {
if(map.size() == k) {
int rk = tail.prev.key;
tail.prev.prev.next = tail;
tail.prev = tail.prev.prev;
map.remove(rk);
}
Node node = new Node(key, val);
map.put(key, node);
moveToHead(node);
}
}
private int get(int key) {
if(map.containsKey(key)) {
Node node = map.get(key);
node.prev.next = node.next;
node.next.prev = node.prev;
moveToHead(node);
return node.val;
}
return -1;
}
private void moveToHead(Node node) {
node.next = head.next;
head.next.prev = node;
head.next = node;
node.prev = head;
}
static class Node{
int key, val;
Node prev, next;
public Node(int key, int val) {
this.key = key;
this.val = val;
}
}
} 34. 单链表的选择排序
模拟...
class Solution {
public:
ListNode* sortInList(ListNode* head) {
// write code here
if(head==NULL) return nullptr;
vector<int> vec;
ListNode * p=head;
while(p!=NULL){
vec.push_back(p->val);
p=p->next;
}
sort(vec.begin(),vec.end());
p=head;
int k=0;
while(p!=NULL){
p->val=vec[k];
k++;p=p->next;
}
return head;
}
}; 35. 链表的奇偶重排
简单模拟
import java.util.*;
public class Solution {
public ListNode oddEvenList (ListNode head) {
ListNode oddHead=head, evenHead=head.next, odd=oddHead, even=evenHead;
while (even!=null && even.next!=null) {
odd.next=even.next;
odd=even.next;
even.next=odd.next;
even=odd.next;
}
odd.next=evenHead;
return oddHead;
}
} 36. 排序
排序
class Solution {
public:
vector<int> MySort(vector<int>& A) {
sort(A.begin(), A.end());
return A;
}
}; 37. 最大数
巧妙处理+处理前导零
class Solution {
public:
string solve(vector<int>& A) {
int n=A.size();
sort(A.begin(), A.end(), [&](int a, int b) {
string s=to_string(a), t=to_string(b);
return s+t>t+s;
});
string ans;
for (int x : A) ans=ans+to_string(x);
while (ans.size()>1 && ans[0]=='0') ans=ans.substr(1);
return ans;
}
}; 38. 数组中出现次数超过一半的数字
简单做一遍即可...
class Solution {
public:
int MoreThanHalfNum_Solution(vector<int> A) {
int n=A.size(), h=n>>1;
unordered_map<int, int> mp;
for (int x : A) {
if (++mp[x]>h) return x;
}
return 0;
}
}; 39. 寻找第K大
不容易想...
import java.util.*;
public class Finder {
public int findKth(int[] a, int n, int K) {
// write code here
return findK(a, 0, n-1, K);
}
public static int partition(int[] arr, int left, int right) {
int pivot = arr[left];
while (left < right) {
while (left < right && arr[right] <= pivot) {
right--;
}
arr[left] = arr[right];
while (left < right && arr[left] >= pivot) {
left++;
}
arr[right] = arr[left];
}
arr[left] = pivot;
return left;
}
public static int findK(int[] arr, int left, int right, int k) {
if (left <= right) {
int pivot = partition(arr, left, right);
if (pivot == k - 1) {
return arr[pivot];
} else if (pivot < k - 1) {
return findK(arr, pivot + 1, right, k);
} else {
return findK(arr, left, pivot - 1, k);
}
}
return -1;
}
} 40. 矩阵元素查找
二分思想
class Finder:
def findElement(self, mat, n, m, x):
i, j = 0, m - 1
while not (i >= n or j < 0):
k = mat[i][j]
if x < k:
j -= 1
elif x > k:
i += 1
else:
return [i, j] 41. 二叉搜索树与双向链表
抽象地一批...
class Solution:
def Convert(self, root):
if not root:
return None
if not root.left and not root.right:
return root
left = self.Convert(root.left)
p = left
while left and p.right:
p = p.right
if left:
p.right = root
root.left = p
right = self.Convert(root.right)
if right:
right.left = root
root.right = right
return left if left else root 42. 合并k个已排序的链表
利用归并排序的思想,将链表合并
public class Solution {
public ListNode mergeKLists(ArrayList<ListNode> lists) {
if(lists==null||lists.size()==0){
return null;
}
return mergeKList(lists,0,lists.size()-1);
}
public ListNode mergeKList(ArrayList<ListNode> lists,int lo,int hi){
if (hi<=lo) return lists.get(lo);
int mid=lo+(hi-lo)/2;
ListNode left = mergeKList(lists,lo,mid);
ListNode right = mergeKList(lists,mid+1,hi);
return merge(left,right);
}
public ListNode merge(ListNode left,ListNode right){
ListNode h = new ListNode(-1);
ListNode tmp=h;
while(left!=null&&right!=null){
if(left.val<right.val){
tmp.next=left;
left=left.next;
}else{
tmp.next=right;
right=right.next;
} tmp=tmp.next; }
if(left!=null){
tmp.next=left;
}
if(right!=null){
tmp.next=right;
}
return h.next;
}
} 43. 在两个长度相等的排序数组中找到上中位数
双指针遍历即可
class Solution {
public:
int findMedianinTwoSortedAray(vector<int>& arr1, vector<int>& arr2) {
int i = -1, j = -1, k = arr1.size() - 1;
bool flag = true;
while (true) {
if (arr1[i + 1] < arr2[j + 1]) {
++i;
if (!flag) flag = true;
}
else {
++j;
if (flag) flag = false;
}
if (i == -1 && j == k || j == -1 && i == k || i + j == k - 1) break;
}
if (flag) return arr1[i];
else return arr2[j];
}
}; 44. 转圈打印矩阵
模拟即可
class Solution {
public int[] printMatrix(int[][] matrix) {
if (matrix == null || matrix.length == 0 || matrix[0].length == 0) {
return new int[0];
}
int m = matrix.length, n = matrix[0].length;
int[] res = new int[m * n];
int rowBegin = 0, rowEnd = m - 1, colBegin = 0, colEnd = n - 1;
int index = 0;
while (rowBegin <= rowEnd && colBegin <= colEnd) {
for (int j = colBegin; j <= colEnd; j++) {
res[index++] = matrix[rowBegin][j];
}
rowBegin++;
for (int i = rowBegin; i <= rowEnd; i++) {
res[index++] = matrix[i][colEnd];
}
colEnd--;
if (rowBegin <= rowEnd) {
for (int j = colEnd; j >= colBegin; j--) {
res[index++] = matrix[rowEnd][j];
}
}
rowEnd--;
if (colBegin <= colEnd) {
for (int i = rowEnd; i >= rowBegin; i--) {
res[index++] = matrix[i][colBegin];
}
}
colBegin++;
}
return res;
}
} 45. 最小的K个数
排序+特判
class Solution {
public:
vector<int> GetLeastNumbers_Solution(vector<int>& A, int k) {
vector<int> ans;
if (A.empty() || k>A.size()) return ans;
sort(A.begin(), A.end());
for (int i=0; i<k; i++) ans.push_back(A[i]);
return ans;
}
}; 46. 矩阵最长递增路径
import java.util.*;
public class Solution {
int[][] dp;
int[] dirs = new int[]{0,1,0,-1,0};
int m, n;
public int solve (int[][] matrix) {
// write code here
int max = 1;
m = matrix.length;
n = matrix[0].length;
dp = new int[m][n];
for(int i = 0; i < m; i++) {
for(int j = 0; j < n; j++) {
max = Math.max(max, dfs(matrix, i, j));
}
}
return max;
}
private int dfs(int[][] matrix, int x, int y) {
if(dp[x][y] != 0) {
return dp[x][y];
}
dp[x][y] = 1;
for(int k = 0; k < 4; k++) {
int nx = x + dirs[k];
int ny = y + dirs[k+1];
if(nx>=0 && nx<m && ny>=0 && ny<n && matrix[nx][ny] < matrix[x][y]) {
dp[x][y] = Math.max(dp[x][y], 1+dfs(matrix, nx, ny));
}
}
return dp[x][y];
}
} 47. 没有重复项数字的所有排列
class Solution {
public:
vector<vector<int>> ans;
int vis[200];
void dfs(vector<int>& v, vector<int>& A) {
if (v.size()>=A.size()) {
ans.push_back(v);
return;
}
for (int i=0; i<A.size(); i++) if (!vis[i]) {
v.push_back(A[i]), vis[i]=1;
dfs(v,A);
v.pop_back(), vis[i]=0;
}
}
vector<vector<int> > permute(vector<int> &A) {
vector<int> v;
dfs(v,A);
return ans;
}
}; 48. 有重复项数字的所有排列
思路:排序+去重
class Solution {
public:
vector<vector<int>> ans;
int vis[200];
void dfs(vector<int>& v, vector<int>& A) {
if (v.size()>=A.size()) {
ans.push_back(v);
return;
}
for (int i=0; i<A.size(); i++) {
if (vis[i] || (i && A[i-1]==A[i] && vis[i-1]))
continue;
v.push_back(A[i]), vis[i]=1;
dfs(v,A);
v.pop_back(), vis[i]=0;
}
}
vector<vector<int> > permuteUnique(vector<int> &A) {
vector<int> v;
sort(A.begin(), A.end());
dfs(v,A);
return ans;
}
}; 49. 加起来和为目标值的组合
思路:去重,一个数字不能选多次
class Solution {
public:
vector<vector<int>> ans;
void dfs(int i, vector<int>& v, vector<int>& A, int tg) {
if (tg==0) {
ans.push_back(v);
return;
}
for (int j=i; j<A.size(); j++) {
if (tg<A[j]) break;
if (j>i && A[j-1]==A[j]) continue;
v.push_back(A[j]);
dfs(j+1,v,A,tg-A[j]);
v.pop_back();
}
}
vector<vector<int>> combinationSum2(vector<int> &A, int tg) {
vector<int> v;
sort(A.begin(), A.end());
dfs(0,v,A,tg);
return ans;
}
}; 50. 数字字符串转化成IP地址
枚举长度+剪枝
class Solution {
public:
vector<string> ans;
void dfs(int i, vector<string>& v, string& s) {
if (i>s.size() || (i<s.size() && v.size()==4)) return;
if (i==s.size() && v.size()==4) {
string t=v[0];
for (int j=1; j<v.size(); j++) t+="."+v[j];
ans.push_back(t);
return;
}
for (int len=1; len<=3; len++) {
string sub=s.substr(i, len);
if (sub[0]=='0' && sub.size()>1) continue;
int n=atoi(sub.c_str());
if (n>=0 && n<=255) {
v.push_back(sub);
dfs(i+len, v, s);
v.pop_back();
}
}
}
vector<string> restoreIpAddresses(string s) {
vector<string> v;
dfs(0,v,s);
return ans;
}
}; 51. 集合的所有子集
思路:简单回溯
class Solution {
public:
vector<vector<int>> ans;
void dfs(int i, vector<int>& v, vector<int> &S) {
if (i==S.size()) return;
v.push_back(S[i]);
ans.push_back(v);
dfs(i+1,v,S);
v.pop_back();
dfs(i+1,v,S);
}
vector<vector<int> > subsets(vector<int> &S) {
vector<int> v;
ans.push_back(v);
dfs(0,v,S);
return ans;
}
}; 52. 分糖果问题
思路:前后递推一遍即可
class Solution {
public:
int candy(vector<int>& A) {
int n=A.size(); vector<int> f(n,1);
for (int i=1; i<n; i++) if (A[i-1]<A[i]) f[i]=f[i-1]+1;
for (int i=n-2; i>=0; i--) if (A[i]>A[i+1]) f[i]=max(f[i+1]+1, f[i]);
return accumulate(f.begin(),f.end(),0);
}
}; 53. 缺失数字
思路:作差法
class Solution {
public:
int solve(int* a, int n) {
int s=n*(n+1)/2, t=accumulate(a,a+n,0);
return s-t;
}
}; 54. 反转数字
分类讨论,感觉说的不清楚,溢出的时候没说是取int的极值啊,全靠猜。。。
#include<bits/stdc++.h>
class Solution {
public:
int reverse(int x) {
string s=to_string(x), t;
bool isNeg=false;
if (!isdigit(s[0])) t=s.substr(1), isNeg=1;
else t=s;
std::reverse(t.begin(),t.end());
long long n=stoll(t);
if (n>INT_MAX) {
n=INT_MAX;
} else if (isNeg) {
n*=-1;
if (n<=INT_MIN) n=INT_MIN;
}
return (int) n;
}
}; 55. 有关阶乘的两个问题1
思路:由于朴素解***超时,利用规律来求:
每次对n!除以5,那么它会把5除干净,由于25也存在两个5,但除以5只得到了一个5,所以还需要除以25得到另外一个无,依次类推
typedef long long ll;
class Solution {
public:
ll thenumberof0(ll n) {
ll c2=0, c5=0, k=5;
while (n>=k) c5+=n/k, k*=5;
return c5;
}
}; 55. 求平方根
使用:规律法,从1开始的连续奇数和一定是一个平方数
public class Solution {
public int sqrt(int x) {
int i = 1;
int res = 0;
while (x >= 0) {
x -= i;
res++;
i += 2;
}
return res - 1;
}
} 56. 丑数
指针版本的动态规划
class Solution:
def GetUglyNumber_Solution(self, index):
if index<=0:
return 0
uglylist=[1]
p2=p3=p5=0
for i in range(index-1):
newugly = min(uglylist[p2]*2,uglylist[p5]*5,uglylist[p3]*3)
uglylist.append(newugly)
if not newugly % 2:
p2+=1
if not newugly %3:
p3+=1
if not newugly %5:
p5+=1
return uglylist[-1] 57. 三个数的最大乘积
定义五个变量,分类讨论
第一次用python,赋值竟然不能一个一个得赋
class Solution:
def solve(self , A):
inf = float('inf')
max1=max2=max3=-inf
min1=min2=inf
for x in A:
if x > max1:
max3, max2, max1 = max2, max1, x
elif x >max2:
max3, max2 = max2, x
elif x > max3:
max3=x
if x < min1:
min2, min1 = min1, x
elif x < min2:
min2=x
return max(max2*max3, min1*min2)*max1
58. 二进制中1的个数
class Solution:
def NumberOf1(self, n):
ans=0
n&=0xffffffff #最小负数的补码为1000 0001,而while进入条件是大于0
while n > 0:
x = n & 1
if x == 1:
ans+=1
n >>= 1
return ans 59. 二叉树的最大深度
递归做就行了
class Solution:
def maxDepth(self , root ):
def dfs(root):
if (root is None):
return 0;
l=dfs(root.left)
r=dfs(root.right)
return max(l,r)+1
return dfs(root) 60. 平衡二叉树
检查左右子树的最大深度差是否大于1
class Solution:
ans=True
def IsBalanced_Solution(self, root):
def dfs(root):
if root is None:
return 0
l=dfs(root.left)
r=dfs(root.right)
if abs(r-l)>1:
self.ans=False
return max(l,r)+1
dfs(root)
return self.ans 61. 判断二叉树是否对称
分类讨论,一定要写两个分路的递归,不然你怎么同时检查左右子树
class Solution:
def isSymmetric(self , root ):
def dfs(l, r):
if l is None and r is None:
return True;
if l is None or r is None:
return False;
return l.val==r.val and dfs(l.left, r.right) and dfs(l.right, r.left)
if root is None:
return True
return dfs(root.left, root.right) 62. 二叉树中是否存在节点和为指定值的路径
简单递归
class Solution:
ans=False
def hasPathSum(self , root , sum ):
def dfs(root, s):
if self.ans or root is None:
return
if root.left is None and root.right is None:
self.ans=(s==root.val)
dfs(root.left, s-root.val)
dfs(root.right, s-root.val)
dfs(root, sum)
return self.ans 63. 将升序数组转化为平衡二叉搜索树
最好不要看样例好。数组的中间位置元素就是BST的根,然后以同样的策略递归构造左、右子树即可
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None
class Solution:
def sortedArrayToBST(self , A ):
def dfs(l,r,A):
if l>=r:
return None
m=l+r>>1
root=TreeNode(A[m])
root.left=dfs(l,m,A)
root.right=dfs(m+1,r,A)
return root
return dfs(0,len(A),A) 64. 二叉树根节点到叶子节点的所有路径和
注意叶子节点的判断
class Solution:
def sumNumbers(self , root ):
def dfs(root, x):
if root is None:
return 0
x=x*10+root.val;
if root.left is None and root.right is None:
return x
return dfs(root.left, x) + dfs(root.right, x)
return dfs(root, 0) 65. 二叉树根节点到叶子节点和为指定值的路径
class Solution:
def pathSum(self , root , sum ):
ans=[]
def dfs(root, s, path):
path=path+[root.val]
if s==root.val and not root.left and not root.right: ans.append(path)
if root.left: dfs(root.left, s-root.val, path)
if root.right: dfs(root.right, s-root.val, path)
path=[]
if not root: return path
dfs(root,sum,path)
return ans;
66. 岛屿数量
栈迭代版本的简单的搜索
class Solution:
def solve(self , g ):
n,m=len(g),len(g[0])
d=[[0,1],[1,0],[-1,0],[0,-1]]
def dfs(x,y,g):
st=[(x,y)]
while st:
x,y=st.pop()
g[x][y]='0'
for k in range(4):
tx,ty=x+d[k][0],y+d[k][1]
if tx>=0 and tx<n and ty>=0 and ty<m and g[tx][ty]=='1':
st.append((tx,ty))
ans=0
for i in range(n):
for j in range(m):
if g[i][j]=='1':
ans+=1
dfs(i,j,g)
return ans 67. 重建二叉树
思路
- 我们先从前序遍历得到根的值 rootVal。
- 然后从中序遍历找出根的下标 rootID 以及根的左子树的大小 leftSize。
- 递归地构造根的左子树和右子树。
class Solution: def reConstructBinaryTree(self, pre, tin): n=len(pre) mp={} for i in range(0,n): mp[tin[i]]=i def dfs(pL,pR,iL,iR): if iL>iR: return None rv=pre[pL] #根的值 rp=mp[rv] #根在中序遍历中的为孩子 lsz=rp-iL #左子树的大小 root=TreeNode(rv) root.left=dfs(pL+1,pL+lsz,iL,rp-1) root.right=dfs(pL+lsz+1,pR,rp+1,iR) return root return dfs(0,n-1,0,n-1)
68. 判断一棵二叉树是否为搜索二叉树和完全二叉树
中序遍历+层序遍历
class Solution {
public:
int pre=INT_MIN;
vector<bool> judgeIt(TreeNode* root) {
// write code here
bool flag1=isSearch(root);
bool flag2=isCom(root);
return {flag1,flag2};
}
bool isSearch(TreeNode*root){
if(root){
bool res=isSearch(root->left);
if(!res) return false;
if(root->val<=pre) return false;
else pre=root->val;
return isSearch(root->right);
}
return true;
}
bool flag=false;
bool isCom(TreeNode* root){
if(root==nullptr) return true;
if(root->left==nullptr&&root->right==nullptr) return true;
if(root->left!=nullptr&&root->right==nullptr){
if(flag) return false;
else flag=true;
}
if(root->left==nullptr&&root->right!=nullptr) return false;
return isCom(root->left)&&isCom(root->right);
}
}; 69. 二叉树的最大路径和
dfs返回的是左右子树的最大和;
因为当前结点我们可以选择,也可以不选,所以当它为负数时,不选最好(0比负数大)
class Solution:
ans=-float('inf')
def maxPathSum(self , root ):
def dfs(root):
if not root: return 0
ls=max(0,dfs(root.left))
rs=max(0,dfs(root.right))
self.ans=max(self.ans,ls+rs+root.val)
return max(ls,rs)+root.val
dfs(root)
return self.ans 70. 合并两个有序的数组
反向思维,哪个大就优先安排在A的末尾,不然python无法通过修改引用指向的方式来修改参数A指向的原数组
class Solution:
def merge(self , A, n, B, m):
i,j,k=n-1,m-1,n+m-1
while ~i and ~j:
if A[i]<B[j]:
A[k]=B[j]
k-=1
j-=1
else:
A[k]=A[i]
k-=1
i-=1
while ~i:
A[k]=A[i]
k-=1
i-=1
while ~j:
A[k]=B[j]
k-=1
j-=1 71. 链表中倒数第k个结点
class Solution:
def FindKthToTail(self, head, k):
if not head: return None
slow,fast=head,head
for i in range(k):
if not fast: return None
fast=fast.next
while fast:
slow=slow.next
fast=fast.next
return slow 72. 链表中环的入口节点
思路:直接存结点
class Solution:
def detectCycle(self , head ):
mp={}
while head:
if head in mp: return head
mp[head]=True
head=head.next
return None 73.删除链表的倒数第n个节点
思路: 双指针,然后修改引用指向即可
class ListNode:
def __init__(self, x):
self.val = x
self.next = None
class Solution:
def removeNthFromEnd(self , head , n ):
dead,slow,fast=ListNode(-1),head,head
dead.next=head
for i in range(n):
fast=fast.next
if not fast: return head.next
while fast and fast.next:
slow=slow.next
fast=fast.next
slow.next=slow.next.next
return dead.next 74. 容器盛水问题
预处理左右的高度差
typedef long long ll;
const int N=1e6+5;
class Solution {
public:
int l[N], r[N];
ll maxWater(vector<int>& A) {
ll n=A.size(), ans=0, lmx=0, rmx=0;
for (int i=0; i<n; i++) {
lmx=max(lmx,(ll) A[i]);
rmx=max(rmx,(ll) A[n-i-1]);
l[i]=lmx-A[i];
r[n-i-1]=rmx-A[n-i-1];
}
for (int i=0; i<n; i++) ans+=min(l[i], r[i]);
return ans;
}
}; 75. 数组中相加和为0的三元组
排序+双指针即可
class Solution:
def threeSum(self , A ):
n,tar,ans=len(A),0,[]
if n<3: return ans
A=sorted(A)
for i in range(n):
if A[i]>0:
break
if i>0 and A[i-1]==A[i]:
continue
l,r=i+1,n-1
while l<r:
s=A[i]+A[l]+A[r]
if s>tar: r-=1
elif s<tar: l+=1
else:
ans.append([A[i],A[l],A[r]])
while l+1<r and A[l]==A[l+1]: l+=1
while r-1>l and A[r]==A[r-1]: r-=1
l+=1
r-=1
return ans 76. 滑动窗口的最大值
思路: 队列维护大小为k的窗口(元素单调递减),只有当i>=k-1时(即遍历够k个元素才输出到ans中)
class Solution:
def maxInWindows(self, A, k):
n,ans,q=len(A),[],[]
if k>n or k==0: return ans
for i in range(n):
while q and A[i]>=A[q[-1]]: q.pop()
q.append(i)
while i-q[0]+1>k: q.pop(0)
if i>=k-1: ans.append(A[q[0]])
return ans 77. 最小覆盖子串
两个计数器
import collections
class Solution:
def minWindow(self, s, t ):
n,m=len(s),len(t)
need=collections.Counter(t)
mp=collections.defaultdict(int)
l,r,ansL,ansR,mi,fd=0,0,0,0,n+5,0
for r in range(n):
c=s[r]
if need[c]:
mp[c]+=1
if (mp[c]==need[c]): fd+=1
while fd==len(need):
if mi>r-l+1:
mi=r-l+1
ansL,ansR=l,r+1
if need[s[l]]:
if mp[s[l]]==need[s[l]]:
fd-=1
mp[s[l]]-=1
l+=1
return s[ansL:ansR] 78. 二分查找
注意边界,以及特殊情况即可
class Solution:
def upper_bound_(self,n,v,a ):
if a[-1]<v: return n+1
l,r=0,n
while l<r:
m=l+r>>1
if a[m]<v:
l=m+1
else:
r=m
return l+1 79. 数字在升序数组中出现的次数
简单二分
class Solution:
def GetNumberOfK(self, A, x):
n=len(A)
def lower_bound():
l,r=0,n
while l<r:
m = l+r>>1
if A[m]>=x: r=m
else: l=m+1
return l
def upper_bound():
l,r=0,n
while l<r:
m=l+r>>1
if A[m]>x:
r=m
else:
l=m+1
return l
return upper_bound()-lower_bound() 80. 旋转数组的最小数字
二分思想+处理重复元素
class Solution:
def minNumberInRotateArray(self, A):
l,r=0,len(A)-1
while l<r:
m=l+r>>1
if A[m]>A[r]: l=m+1 #[m,r]为升序数组,且A[m]不可能成为答案
elif A[m]<A[r]: r=m #[m,r]为降序数组,且A[m]有可能作为答案
else: r-=1
return A[l] 81. 矩阵查找
二分思想
class Solution:
def searchMatrix(self , g , x ):
n,m=len(g),len(g[0])
i,j=0,m-1
while i<n and j>=0:
if x>g[i][j]: i+=1
elif x<g[i][j]: j-=1
else: return True
return False 82. 在转动过的有序数组中寻找目标值
确定升序区间,在确定x在升序区间中的位置
class Solution:
def search(self , A , x ):
l,r=0,len(A)-1
while l<=r:
m=l+r>>1
if x==A[m]: return m
# [l,m]是升序
if A[l]<=A[m]:
if A[l]<=x and x<=A[m]: r=m-1
else: l=m+1
# [m,r]是升序
else:
if x>=A[m] and x<=A[r]: l=m+1
else: r=m
return -1 83. 完全二叉树结点数
数是完全二叉树,如果左子树的树高与右子树相同,则表示左子树是满二叉树;否则,左子树的树高一定大于右子树,所以右子树是满二叉树

class Solution:
def nodeNum(self , root ):
def getH(root):
h=0
while root:
root=root.left
h+=1
return h
if not root: return 0
lh=getH(root.left)
rh=getH(root.right)
if lh==rh: return (1<<lh)+self.nodeNum(root.right)
else: return (1<<rh)+self.nodeNum(root.left) 84. 寻找峰值
从后往前遍历到第一个升序结构即为山峰
class Solution:
def solve(self , A ):
for i in range(len(A)-1, 0, -1):
if A[i-1]<A[i]:
return i 85. 最长递增子序列
还是比较难想的一道题:
- dp[i]表示到arr[i]为止最长的递增子序列
- res用来存储字典序最小的最长子序列,倒序遍历dp,即可
class Solution { public: vector<int> LIS(vector<int>& A) { int n=A.size(); vector<int> dp(n); vector<int> minnum(n); int k=0; for(int i=0;i<n;i++){ if(k==0||A[i]>minnum[k-1]){ dp[i]=k; minnum[k++]=A[i]; } else{ int l=0,r=k; while(l<=r){ int mid=(l+r)/2; if(minnum[mid]<A[i]) l=mid+1; else r=mid-1; } minnum[l]=A[i]; dp[i]=l; } } vector<int> res(k); k--; for(int i=n-1;i>=0;i--){ if(dp[i]==k) res[k--]=A[i]; } return res; } };
86. 在两个长度相等的排序数组中找到上中位数
思路:双指针即可
import java.util.*;
public class Solution {
public int findMedianinTwoSortedAray (int[] A, int[] B) {
int p1=0,p2=0,mid=0;
for(int i=0;i<A.length;i++){
if(A[p1]<=B[p2]){
mid=A[p1];
p1++;
}else{
mid=B[p2];
p2++;
}
}
return mid;
}
} 87. 数组中只出现一次的数字
简单计数题,位运算没想到
import collections
class Solution:
def FindNumsAppearOnce(self, A):
cnt=collections.defaultdict()
for x in A: cnt[x]=cnt.get(x,0)+1
ans=[]
for k,v in cnt.items():
if v==1: ans.append(k)
return ans 相同的数字异或的结果为0,不同的数字的疑惑结果至少有一个位置的二进制位不同(这里为了方便,取最低位的1,假设在位置k);把数组分成两组:
- 一组是第k位没有1
- 一组是第k位有1
这样异或下来,就可以找到两个数字了
class Solution:
def FindNumsAppearOnce(self, A):
n=len(A)
x,y,t=0,0,0
for v in A: t^=v
k=0 #t的最后一位1的位置
for i in range(32):
if (t>>i)&1==1:
k=i
break
for v in A:
if (v>>k)&1==1: x^=v
else: y^=v
return [x,y] 88. 进制转换
思路: 注意负数,以及n大于9时的特殊情况即可
class Solution:
def solve(self, m, n):
def get(x):
if 0<=x and x<10: return str(x)
return chr(x-10+65)
isNeg=False
if m<0:
m=-m
isNeg=True
ans=''
while m>0:
ans=get(m%n)+ans
m/=n
return '-'+ans if isNeg else ans 89. 数组中的最长连续子序列
思路:排序+统计连续的数字的个数
class Solution {
public:
int MLS(vector<int>& A) {
sort(A.begin(), A.end());
int n=A.size(), ans=1, cur=1;
for (int i=1; i<n; i++) if (A[i-1]!=A[i]) {
if (A[i-1]+1==A[i]) {
cur++;
ans=max(ans, cur);
} else {
cur=1; //遇到不连续的就赋初值
}
}
return ans;
}
}; 90. 求二叉树的层序遍历
思路: 记录深度的递归求解
class Solution:
def levelOrder(self , root ):
ans=[]
def dfs(root, d):
if not root: return
if len(ans)==d: ans.append([root.val])
else: ans[d].append(root.val)
dfs(root.left, d+1)
dfs(root.right, d+1)
dfs(root,0)
return ans 91. 把二叉树打印成多行
思路: 层序遍历+py的细节处理即可
class Solution:
def Print(self, root):
if not root: return []
ans,q=[],[]
d=0
q.append(root)
while q:
sz=len(q)
for i in range(sz):
t=q.pop(0)
if len(ans)==d: ans.appe***al])
else: ans[d].appe***al)
if t.left: q.append(t.left)
if t.right: q.append(t.right)
d+=1
return ans 92. 二叉树的之字形层序遍历
思路: 层序遍历+奇数层逆序
class Solution:
def zigzagLevelOrder(self , root ):
if not root: return []
ans,q=[],[]
d=0
q.append(root)
while q:
sz=len(q)
for i in range(sz):
t=q.pop(0)
if len(ans)==d: ans.appe***al])
else: ans[d].appe***al)
if t.left: q.append(t.left)
if t.right: q.append(t.right)
if d&1: ans[d].reverse()
d+=1
return ans 93. 用两个栈实现队列
思路:
题意清晰很友好,直接两个栈实现队列(用一个缓存栈临时存储数据)
class Solution:
st,cache=[],[]
def push(self, x):
self.st.append(x)
def pop(self):
while self.st:
self.cache.append(self.st[-1])
self.st.pop(-1)
ans=self.cache.pop(-1)
while self.cache:
self.st.append(self.cache[-1])
self.cache.pop(-1)
return ans 94. 设计getMin功能的栈
思路: 双栈伺候,因为要存储过程中的全部最小值,所以需要另一个栈存储越新鲜的最小值
class Solution:
def getMinStack(self , ops ):
st,mst,ans=[],[],[]
for op in ops:
if op[0]==1:
st.append(op[1])
if not mst or mst[-1]>op[1]:
mst.append(op[1])
elif op[0]==2:
top=st.pop(-1)
if mst and mst[-1]==top:
mst.pop(-1)
else:
ans.append(mst[-1])
return ans 95. 实现二叉树先序,中序和后序遍历
思路: 啊这,换个位置?说什么呢?正经思路是:
先序:根左右
中序:左根右
后序:左右根
递归版本没啥难度
class Solution:
def threeOrders(self , root ):
pre,inn,post=[],[],[]
def dfs(root):
if not root: return
pre.append(root.val)
dfs(root.left)
inn.append(root.val)
dfs(root.right)
post.append(root.val)
dfs(root)
ans=[pre,inn,post]
return ans 96. 表达式求值
思路:
- 用栈保存各部分计算的和
- 遇到数字时继续遍历求这个完整的数字的值
- 遇到(时递归求括号里面的值
class Solution { public: int solve(string s) { int k=0; return helper(s,k); } int helper(string s,int &index){ stack<int> s1; char sign='+'; int res=0; for( index;index<s.size();index++){ if(isdigit(s[index])){ res=res*10+(s[index]-'0'); } if(s[index]=='+'||s[index]=='-'||s[index]=='*'||(index==s.size()-1)){ if(sign=='+'){ s1.push(res); }else if(sign=='-') { s1.push(-res); }else{ int k1=s1.top(); s1.pop(); s1.push(k1*res); } res=0; sign=s[index]; } if(s[index]=='('){ index++; res=helper(s,index); }else if(s[index]==')'){ break; } } if(res!=0){ if(sign=='+'){ s1.push(res); }else if(sign=='-') { s1.push(-res); }else{ int k1=s1.top(); s1.pop(); s1.push(k1*res); } } int sum=0; while(!s1.empty()){ sum+=s1.top(); s1.pop(); } return sum; } };
97. 栈和排序
思路: 贪心+栈
顺序遍历数组时,怎样才能知道后面的元素是否有大于自己的呢,答案是数组预处理
因为FILO的特性,我们要先把栈中的大元素先弄进ans
const int N=1e6+5;
class Solution {
public:
int mx[N];
vector<int> solve(int* A, int n) {
vector<int> ans;
stack<int> st;
memset(mx, -1, sizeof mx);
for (int i=n-1; ~i; i--) mx[i]=max(mx[i+1], A[i]);
for (int i=0; i<n; i++) {
st.push(A[i]);
if (mx[i]==A[i]) {
ans.push_back(st.top()), st.pop();
while (i+1<n && !st.empty() && st.top()>mx[i+1])
ans.push_back(st.top()), st.pop();
}
}
while (!st.empty()) ans.push_back(st.top()), st.pop();
return ans;
}
}; 98. 序列化二叉树
思路: 只要是能遍历一棵树的方法都行,这里采用层序遍历
function TreeNode(x) {
this.val = x;
this.left = null;
this.right = null;
}
function Serialize(pRoot)
{
if (!pRoot) return "";
let res = [];
let tree = [pRoot];
while (tree.length) {
let len = tree.length;
for (let i = 0; i < len; i++) {
let node = tree.shift();
if (!node) {
res.push("#");
continue;
}
res.push(node.val);
tree.push(node.left, node.right);
}
}
return res.join(" ");
}
function Deserialize(s)
{
if (!s) return null;
let arr = s.split(/\s/g);
let root = new TreeNode(arr[0]);
let tree = [root];
let i = 1;
while (tree.length){
let node = tree.shift();
if (!node) continue;
node.left = arr[i] !== "#" ? new TreeNode(arr[i]) : null;
node.right = arr[i + 1] !== "#" ? new TreeNode(arr[i + 1]) : null;
i += 2;
tree.push(node.left, node.right);
}
return root;
}
module.exports = {
Serialize : Serialize,
Deserialize : Deserialize
}; 99. 合并二叉树
思路: 始终以一棵树为基准进行合并,且返回这个节点
class Solution:
def mergeTrees(self , t1 , t2 ):
def dfs(p, q):
if not ***ot q: return p if p else q
p.val+=q.val
p.left=dfs(p.left, q.left)
p.right=dfs(p.right, q.right)
return p
return dfs(t1,t2) 100. 二叉树的镜像
思路: 不断交换即可,不难
class Solution:
def Mirror(self, root):
def dfs(root):
if not root: return
root.left,root.right=root.right,root.left
dfs(root.left)
dfs(root.right)
dfs(root)
return root 101. 判断t1树中是否有与t2树拓扑结构完全相同的子树
思路: 双指针判断子序列的思想
public class Solution {
public boolean isContains (TreeNode p, TreeNode q) {
if (q==null) return true;
if (p==null) return false;
if (p.val==q.val) return isContains(p.left, q.left) && isContains(p.right, q.right);
return isContains(p.left, q) || isContains(p.right, q);
}
} 102. 树的直径
思路: 记录最大与次大即可
class Solution {
public:
int ans = INT_MIN;
int solve(int n, vector<Interval>& Tree_edge, vector<int>& Edge_value) {
vector<vector<pair<int,int>> > g(n);
for(int i = 0; i < Tree_edge.size(); i++){
auto e = Tree_edge[i];
g[e.start].push_back(make_pair(e.end, Edge_value[i]));
g[e.end].push_back(make_pair(e.start, Edge_value[i]));
}
int pre = -1, cur = 0;
dfs(g, pre, cur);
return ans;
}
int dfs(vector<vector<pair<int,int>> >& g, int pre, int cur){
int d1 = 0, d2 = 0;//d1保最大值,d2保存次大值
for(int i = 0; i < g[cur].size(); i++){
int node = g[cur][i].first;//当前节点相连接的下一个节点
if(node != pre){//判断当前的节点不是和它相连接的上一个节点
int d = dfs(g, cur, node) + g[cur][i].second;
if(d > d1){
d2 = d1;
d1 = d;
}else if(d > d2){
d2 = d;
}
}
}
ans = max(ans, d1 + d2);//保存当前遍历过的元素的最大路径
return d1;
}
}; 103. 二叉搜索树的第k个结点
思路: 非递归模拟计算机压栈退栈
class Solution:
def KthNode(self, root, k):
ans,p,st=None,root,[]
while st or p:
if p:
st.append(p)
p=p.left
else:
p=st.pop()
if k-1==0: return p
k-=1
p=p.right
return None 104. 输出二叉树的右视图
思路: 构造二叉树,然后优先遍历右子树,在遍历左子树
import collections
class Solution:
def solve(self, pre, inn):
def dfs(pL, pR, iL, iR, pre, inn):
if pL>pR: return None
rp=mp[pre[pL]]
lsz=rp-iL
root=TreeNode(pre[pL])
root.left=dfs(pL+1,pL+lsz,iL,rp-1,pre,inn)
root.right=dfs(pL+lsz+1,pR,rp+1,iR,pre,inn)
return root
n,mp=len(pre),collections.defaultdict(int)
for i in range(n): mp[inn[i]]=i
root=dfs(0,n-1,0,n-1,pre,inn)
def get(root,ans,d):
if not root: return
if d==len(ans): ans.append(root.val)
get(root.right,ans,d+1)
get(root.left,ans,d+1)
ans=[]
get(root,ans,0)
return ans 105. 在二叉树中找到两个节点的最近公共祖先
思路: 遍历q及其父节点,如果list的父节点中含有,则返回,即为最近的共同祖先
import java.util.*;
public class Solution {
HashMap<Integer,Integer> mp = new HashMap<>();
public int lowestCommonAncestor (TreeNode root, int p, int q) {
if(root.val==p||root.val==q) return root.val;
ArrayList<Integer> list = new ArrayList<>();
dfs(root);
list.add(p);
while(mp.get(p)!=null){
list.add(mp.get(p));
p = mp.get(p);
}
if(list.contains(q)) return q;
//遍历q的祖先,找出最近的公共祖先
while(mp.get(q)!=null){
q = mp.get(q);
if(list.contains(q)) return q;
}
return -1;
}
void dfs(TreeNode root){
if(root.left!=null){
mp.put(root.left.val,root.val);
dfs(root.left);
}
if(root.right!=null){
mp.put(root.right.val,root.val);
dfs(root.right);
}
}
} 106. 找到搜索二叉树中两个错误的节点
思路: 中序遍历+用pre记录当前结点的前一个结点,两个结点交换了会发生什么?第一个降序结构的第一个结点是err[0],最后一个降序结构的第一个结点是err[1]
class Solution {
public:
vector<int> findError(TreeNode* root) {
stack<TreeNode*> st;
TreeNode* pre=NULL;
int u=-1,v;
while (!st.empty() || root!=NULL) {
if (root!=NULL) {
st.push(root);
root=root->left;
} else {
root=st.top(); st.pop();
if (pre!=NULL && pre->val>root->val) {
if (u==-1) u=pre->val;
v=root->val;
}
pre=root;
root=root->right;
}
}
return {v,u};
}
}; 107. 两数之和
思路: 直接map记录数字的位置
import collections
class Solution:
def twoSum(self , A , tar ):
n=len(A)
mp=collections.defaultdict(int)
for i in range(n):
if mp.get(tar-A[i]): return [mp[tar-A[i]], i+1]
mp[A[i]]=i+1
return [] 108. 未排序数组中累加和为给定值的最长子数组长度
思路: mp记录前缀和的位置,前缀和0的位置默认为0(特殊处理)
import collections
class Solution:
def maxlenEqualK(self , A , k ):
n,s,ans=len(A),0,0
mp={0:-1}
for i in range(n):
s+=A[i]
if s-k in mp:
ans=max(ans, i-mp[s-k])
if s not in mp:
mp[s]=i
return ans 109. 出现次数的TopK问题
思路: 先对数组排序,在用map统计频次,over
import collections
class Solution:
def topKstrings(self , A , k ):
A.sort()
cnt=collections.defaultdict(int)
for s in A:
cnt[s]+=1
list=sorted(cnt.items(), key=lambda x:x[1], reverse=True)
return [[str(list[i][0]), str(list[i][1])] for i in range(k)] 110. 找到字符串的最长无重复字符子串
思路: 字典记录每个数字出现的位置,双指针做即可
class Solution:
def maxLength(self , A ):
my_dict = {}
left, right = 0, 0
n,ans = len(A), float('-inf')
while right<=n-1:
if not A[right] in my_dict:
my_dict[A[right]] = right
right += 1
else:
ans = max(ans, right - left)
for i in range(left, my_dict[A[right]]):
my_dict.pop(A[i])
left = my_dict[A[right]]+1
my_dict[A[right]] = right
right += 1
ans = max(ans, right - left)
return ans 111. 数独
思路: 简单回溯,能否填数字即可
class Solution:
def solveSudoku(self , g ):
num_set = set([str(i) for i in range(1,10)])
v_set = [set() for i in range(9)]
h_set = [set() for i in range(9)]
s_set = [set() for i in range(9)]
def get_part(x,y):
return x//3*3+y//3
def set_num(x,y,num):
v_set[x].add(num)
h_set[y].add(num)
s_set[x//3*3+y//3].add(num)
g[x][y] = num
def remove_num(x,y,num):
v_set[x].remove(num)
h_set[y].remove(num)
s_set[x//3*3+y//3].remove(num)
g[x][y] = "."
for i in range(9):
for j in range(9):
if g[i][j]!=".":
v_set[i].add(g[i][j])
h_set[j].add(g[i][j])
s_set[i//3*3+j//3].add(g[i][j])
def is_valid(x,y,num):
if num not in v_set[x] and num not in h_set[y] and num not in s_set[x//3*3+y//3]:
return True
return False
def backtrack(x,y):
if x>8:
return True
if y>8:
return backtrack(x+1,0)
if g[x][y]!=".":
return backtrack(x,y+1)
for i in range(1,10):
str_i = str(i)
if is_valid(x,y,str_i):
set_num(x,y,str_i)
if backtrack(x,y+1):
return True
remove_num(x,y,str_i)
return False
backtrack(0,0)
return g 112. 随时找到数据流的中位数(*)
113. 跳台阶
思路: 简单递推
class Solution:
def jumpFloor(self, n):
f=[0]*(int(1e5+5))
f[0]=f[1]=1
for i in range(2,n+1):
f[i]=f[i-1]+f[i-2]
return f[n] 114. 拼接所有的字符串产生字典序最小的字符串
思路: a<b,则有:a+b<b+a
class Solution {
public:
string minString(vector<string>& A) {
string ans;
sort(A.begin(), A.end(), [&](const string& a, const string& b) {
return a+b<b+a;
});
for (string& s : A) ans+=s;
return ans;
}
}; 115. 丢棋子问题(*)
思路:
116. 二叉搜索树与双向链表
思路: 记录当前结点的前驱结点
class Solution:
forword,head=None,None
def Convert(self , root ):
def dfs(root):
if not root: return
dfs(root.left)
if not self.head:
self.forword=root
self.head=root
else:
self.forword.right=root
root.left=self.forword
self.forword=root
dfs(root.right)
dfs(root)
return self.head 117. 顺时针旋转矩阵
class Rotate:
def rotateMatrix(self, g, n):
ans=[[0]*n for i in range(n)]
for i in range(n):
for j in range(n):
ans[j][n-i-1]=g[i][j]
return ans 118. 螺旋矩阵
思路: 不断换方向即可,简单模拟
class Solution:
def spiralOrder(self , matrix ):
res = [];
if (len(matrix) == 0 or len(matrix[0]) == 0):
return res;
rowBegin = 0;
rowEnd = len(matrix) - 1;
colBegin = 0;
colEnd = len(matrix[0]) - 1;
while (rowBegin <= rowEnd and colBegin <= colEnd) :
# Traverse Right
for j in range(colBegin, colEnd+1, 1):
res.append(matrix[rowBegin][j]);
rowBegin += 1
# Traverse Down
for j in range(rowBegin, rowEnd+1, 1):
res.append(matrix[j][colEnd]);
colEnd -= 1
if (rowBegin > rowEnd or colBegin > colEnd) :
break;
# Traverse Left
for j in range(colEnd, colBegin-1, -1):
res.append(matrix[rowEnd][j]);
rowEnd -= 1
# Traverse Up
for j in range(rowEnd, rowBegin-1, -1):
res.append(matrix[j][colBegin]);
colBegin += 1
return res; 119. 合并区间
思路: 先按start升序排序,然后如果有重叠,则判断是两个区间合起来后包含还是扩展,没有重叠直接加到ans即可
class Solution:
def merge(self , A ):
n,ans=len(A),[]
A.sort(key=lambda x : x.start)
for e in A:
if ans and ans[-1].end>=e.start:
ans[-1].end=max(ans[-1].end, e.end)
else:
ans.append(e)
return ans 120. N皇后问题
import java.util.*;
public class Solution {
private int count = 0;
public int Nqueen(int n) {
if (n < 1) return 0;
dfs(0,0,0,0,n);
return count;
}
private void dfs(int row, int col, int pie, int na,int n) {
if (row >= n) {
count++;
return;
}
int bit = (~(col | pie | na))
& ((1<<n) - 1); // 去掉所有高位
while (bit > 0) {
int p = bit & -bit;
dfs(row + 1,col | p,(pie | p ) << 1,(na | p) >> 1,n);
bit &= (bit - 1);
}
}
} 121. 数组中未出现的最小正整数
思路: ans记录最小正数,set记录整数的出现,只要是连续的,就记录下来
import collections
class Solution:
def minNumberdisappered(self, A):
ans=1
st=collections.defaultdict(bool)
for x in A:
st[x]=1
while (st.get(ans,False)): ans+=1
return ans 122. 数组中未出现的最小正整数
思路: 作差法(前提是要保证A加上这个缺失的数字是连续数组)
class Solution:
def minNumberdisappered(self, A):
s1=s2=0
mi,mx=float('inf'),-float('inf')
for x in A:
mi=min(mi,x)
mx=max(mx,x)
s1+=x
for i in range(mi,mx+1):
s2+=i
ans=mx+1 if s1==s2 else s2-s1 #没有/有缺失的正数
return max(1,ans) 123. 回文数字
思路: 从低位开始取即可
import sys
class Solution:
def isPalindrome(self, x: int) -> bool:
t,v,inf=x,0,sys.maxsize
if x<0: return False
while x:
dig=x%10
v=v*10+dig
x=x//10
if v>inf: v=inf
return t==v 124. 扑克牌顺子
思路: 从数组中的最小值开始,检查是否可以用有限的0代替缺失的数字,如果能,返回true;当然,一种特殊情况
class Solution:
def IsContinuous(self, A):
if not A: return False
n,cnt,mp=len(A),[0],[False]*50
mi,mx=float('inf'),-float('inf')
for x in A:
if x==0:
cnt[x]+=1
else:
mp[x]=True
mi=min(mi,x)
mx=max(mx,x)
l=0
for i in range(mi,mx+1):
if mp[i]:
l+=1
else:
if cnt[0]>0:
cnt[0]-=1
l+=1
else:
return False
if l<n:
while cnt[0]>0:
l+=1
cnt[0]-=1
return l==n 125. 斐波那契数列
思路: 简单递推
class Solution:
def Fibonacci(self, n):
if not n: return 0
a,b,c=0,1,1
for i in range(n-2):
a=b
b=c
c=a+b
return c 126. 单链表的排序
思路:先存储后到列表中,链接成链表
class Solution:
def sortInList(self , head ):
A=[]
ans,t=ListNode(-1),head
while t:
A.appe***al)
t=t.next
A.sort()
cur=ListNode(A[0])
ans.next=cur
for i in range(1,len(A)):
nxt=ListNode(A[i])
cur.next=nxt
cur=nxt
return ans.next 126. 括号生成
思路:先放左括号,再放右括号
class Solution:
def generateParenthesis(self , n ):
def dfs(l,r,s,A):
if l==0 and r==0:
A.append(s)
return
if l>0: dfs(l-1,r,s+'(',A)
if l<r: dfs(l,r-1,s+')',A)
A=[]
dfs(n,n,'',A)
return A 127. 调整数组顺序使奇数位于偶数前面
思路:开两个数组,分别存储偶数和奇数
class Solution:
def reOrderArray(self , A ):
oi,ei,loi,lei,n=-1,-1,-1,-1,len(A)
B,C=[],[]
for i in range(n):
if A[i]&1: B.append(A[i])
else: C.append(A[i])
B+=C
return B 128. 字符串变形
思路:翻转单词即可
class Transform:
def trans(self, s, n):
ans=''
for c in s:
if c==' ': ans+=c
elif c.isupper(): ans+=c.lower()
else: ans+=c.upper()
A=ans.split(' ')
return ' '.join(A[::-1]) 129. 将字符串转化为整数
思路:注意细节即可
class Solution:
def atoi(self , str ):
min_int = -(1<<31)
max_int = (1<<31)-1
str = str.strip()
if str == '': return 0
sign = 1
if str[0] == '-':
sign = -1
str = str[1: len(str)]
elif str[0] == '+':
str = str[1: len(str)]
length, end = len(str), len(str)
for i in range(length):
if str[i]>='0' and str[i]<='9': continue
else:
end = i
break
str = str[0: end]
if str == '': return 0
else:
ans = sign*int(str)
if ans < min_int:
ans = min_int
if ans > max_int:
ans = max_int
return ans 130. 比较版本号
思路:遇到数字则累加,两个指针遇到.时则比较数字大小
class Solution:
def compare(self , s: str, t: str):
i,j,n,m=0,0,len(s),len(t)
a=b=0
while i<n and j<m:
if s[i].isdigit():
a=a*10+int(s[i])
i+=1
if t[j].isdigit():
b=b*10+int(t[j])
j+=1
if i<n and j<m and s[i]=='.' and t[j]=='.':
if a<b: return -1
elif a>b: return 1
a=b=0
i,j=i+1,j+1
if n-i==m-j: return 0
return -1 if n-i<m-j else 1 131. 设计LRU缓存结构
思路:模拟即可,代码有点多
class Solution {
public:
vector<int>ans;
vector<int> LRU(vector<vector<int> >& operators, int k) {
vector<int> r;
vector<int> key;
for(int i = 0; i < operators.size(); i++){
if(operators[i][0] == 1){
set(operators[i][1], operators[i][2], r, key, k);
}
if(operators[i][0] == 2){
get(operators[i][1], r, key);
}
}
return ans;
}
void set(int a, int b, vector<int> &r, vector<int> &key, int k){
if(r.size() < k){
key.push_back(a);
r.push_back(b);
}
else{
key.erase(key.begin());
r.erase(r.begin());
key.push_back(a);
r.push_back(b);
}
}
void get(int a, vector<int> &r, vector<int> &key){
int t = -1;
for(int i = 0; i < key.size(); i++){
if(a == key[i]){
t = i;
break;
}
}
if(t == -1){
ans.push_back(-1);
}
else{
int t1, t2;
t1 = key[t];
t2 = r[t];
key.erase(key.begin() + t);
r.erase(r.begin() + t);
key.push_back(t1);
r.push_back(t2);
ans.push_back(t2);
}
}
}; 132. 判断回文
思路:双指针遍历判断即可
class Solution:
def judge(self , s ):
l,r=0,len(s)-1
while l<r:
if s[l]!=s[r]: return False
l,r=l+1,r-1
return True 132. 旋转字符串
思路:枚举每一种情况即可
class Solution:
def solve(self , A , B ):
n=len(A)
for i in range(1,n):
fir,sec=A[0:i],A[i:]
t=sec+fir
if t==B: return True
return False 133. 旋转数组
思路:模拟即可
class Solution {
public:
vector<int> solve(int n, int m, vector<int>& a) {
vector<int> d;
int finished = 0, count = a.size();
for (int i=0; i < count; ++i) {
if (finished >= count)
break;
int begin = i;
int cur = i;
int tmp = a[cur];
int prev = prev_index(cur, m, n);
while (begin != prev) {
d.push_back(cur);
d.push_back(prev);
d.push_back(0);
finished++;
a[cur] = a[prev];
cur = prev;
prev = get(cur, m, n);
}
finished++;
d.push_back(cur);
d.push_back(tmp);
d.push_back(0);
a[cur] = tmp;
}
for (auto& i : a) d.push_back(i);
return a;
}
int get(int i, int len, int count) {
i -= len;
while (i < 0) i += count;
return i;
}
}; 134. 验证IP地址
思路:模拟即可
class Solution:
def solve(self , s ):
def isIPV4(A):
for s in A:
if s.startswith("0") or len(s)>3 or int(s)>255: return False
return True
def isIPV6(A):
for s in A:
if len(s)>4: return False
return True
A=s.split(".")
B=s.split(":")
if not isIPV4(A) and not isIPV6(B): return "Neither"
return "IPv4" if isIPV4(A) else "IPv6" 135. 数组中的逆序对
思路:双指针模拟即可
class Solution:
ans,mod=0,int(1e9+7)
def InversePairs(self, A):
def merge_sort(l,r,A):
if l>=r: return
m=l+r>>1
merge_sort(l,m,A)
merge_sort(m+1,r,A)
i,j,B=l,m+1,[]
while i<=m and j<=r:
if A[i]<A[j]:
B.append(A[i])
i+=1
else:
B.append(A[j])
self.ans+=m-i+1
j+=1
while i<=m:
B.append(A[i])
i+=1
while j<=r:
B.append(A[j])
j+=1
i,j=l,0
while i<=r:
A[i]=B[j]
i,j=i+1,j+1
n=len(A)
merge_sort(0,n-1,A)
return self.ans%self.mod 136. 字典树的实现
思路:直接用列表实现
class Solution:
def trieU(self , operators ):
strs, result = [],[]
for i in range(len(operators)):
case = int(operators[i][0])
string = operators[i][1]
if case == 1:
self.add(strs, string)
elif case == 2:
self.delete(strs, string)
elif case == 3:
self.search(strs, string, result)
elif case == 4:
self.cnt(strs, string, result)
return result
def add(self, strs, string):
strs.append(string)
def delete(self, strs, string):
idx = strs.index(string)
del strs[idx]
def search(self, strs, string, result):
if string in strs:
result.append('YES')
else:
result.append('NO')
def cnt(self, strs, string, result):
count = 0
if len(strs) > 0:
for s in strs:
if s.startswith(string):
count += 1
result.append(str(count)) 137. 孩子们的游戏(圆圈中最后剩下的数)
思路:m模拟即可
class Solution:
def LastRemaining_Solution(self, n, m):
i,A=0,list(range(n))
while len(A)>1:
i=(i+m-1)%len(A)
A.pop(i)
return -1 if len(A)==0 else A[0] 138. 环形链表的约瑟夫问题
思路:模拟即可
class Solution {
public:
int dfs(int n, int m) {
if (n==1) return 0;
int j=dfs(n-1,m);
return (j+m)%n;
}
int ysf(int n, int m) {
return dfs(n,m)+1;
}
}; 139. 矩阵最长递增路径
思路:f用局部变量可以过,用全局变量不可以过
const int N=2005, dir[4][2] = { {1,0},{0,-1},{0,1},{-1,0} };
class Solution {
public:
int n,m,ans=1;
int dfs(int x, int y, vector<vector<int>>& f, vector<vector<int> >& g) {
if (f[x][y]) return f[x][y];
int mx=1;
for (auto& d : dir) {
int tx=x+d[0], ty=y+d[1];
if (tx>=0 && tx<n && ty>=0 && ty<m && g[tx][ty]>g[x][y])
mx=max(mx,dfs(tx,ty,f,g)+1);
}
return f[x][y]=mx;
}
int solve(vector<vector<int>>& g) {
if (g.empty() || g[0].empty()) return 0;
n=g.size(), m=g[0].size();
vector<vector<int>> f(m, vector<int>(n, 0));
for (int i=0; i<n; i++)
for (int j=0; j<m; j++)
ans=max(ans,dfs(i,j,f,g));
return ans;
}
}; 140. 矩阵乘法
思路:线性代数知识,你不会就是不会
class Solution {
public:
vector<vector<int> > solve(vector<vector<int> >& a, vector<vector<int> >& b) {
int n=a.size();
vector<vector<int>> c(n,vector<int>(n,0));
for (int i=0; i<n; i++)
for (int j=0; j<n; j++)
for (int k=0; k<n; k++) {
c[i][j]+=a[i][k]*b[k][j];
}
return c;
}
}; 141. 最长重复子串
思路:枚举长度+合法性检测
class Solution {
public:
bool valid(int l, int len, string& s) {
for (int i=l; i<l+len; i++) if (s[i]!=s[i+len])
return false;
return true;
}
int solve(string& s) {
int n=s.size();
for (int len=n/2; len>0; len--) {
for (int i=0; i<=n-2*len; i++) {
if (valid(i,len,s))
return 2*len;
}
}
return -1;
}
}; 142. 随时找到数据流的中位数
思路:两个堆
class Solution {
public:
priority_queue<int, vector<int>, greater<int>> minQ;
priority_queue<int> maxQ;
void addNum(int x) {
maxQ.push(x);
minQ.push(maxQ.top()), maxQ.pop();
if (minQ.size()>maxQ.size()+1)
maxQ.push(minQ.top()), minQ.pop();
}
double findMedian() {
if (minQ.empty()) return -1;
return minQ.size()!=maxQ.si***Q.top() : (minQ.top()+maxQ.top())*0.5;
}
vector<double> flowmedian(vector<vector<int> >& ops) {
vector<double> ans;
for (auto& op : ops) {
if (op[0]==1) {
addNum(op[1]);
} else { //查询
ans.push_back(findMedian());
}
}
return ans;
}
}; 143. 划分链表
思路:双指针+细节,因为最后如果b的next不为空的话,将会导致循环引用
class Solution:
def partition(self , head , x ):
dead1,dead2=ListNode(0),ListNode(0)
a, b=dead1, dead2 #a是小于x的结点,b是所有大于等于x的结点
while (head):
if (head.val < x):
a.next=head
a=a.next
else:
b.next=head
b=b.next
head=head.next
a.next=dead2.next
b.next=None
return dead1.next 144. LFU缓存结构设计
思路:map+双向链表
import java.util.*;
public class Solution {
public class LFUCache {
private class Node {
int k;
int v;
int count;
public Node(int k, int v) {
this.k = k;
this.v = v;
count = 1;
}
}
private int size;
private int maxSize;
private Map<Integer, Node> key2node;
private Map<Integer, LinkedList<Node>> count2list;
public LFUCache(int maxSize) {
this.maxSize = maxSize;
size = 0;
key2node = new HashMap<>();
count2list = new HashMap<>();
}
public void set(int k, int v) {
if (key2node.containsKey(k)) {
key2node.get(k).v = v;
get(k);
return;
}
Node node = new Node(k, v);
if (!count2list.containsKey(node.count)) count2list.put(node.count, new LinkedList<>());
LinkedList<Node> list = count2list.get(node.count);
list.addFirst(node);
key2node.put(k, node);
size++;
if (size > maxSize) {
key2node.remove(list.getLast().k);
list.removeLast();
size--;
}
}
public int get(int k) {
if (!key2node.containsKey(k)) return -1;
Node node = key2node.get(k);
LinkedList<Node> oldList = count2list.get(node.count);
oldList.remove(node);
if (oldList.isEmpty()) count2list.remove(node.count);
node.count++;
if (!count2list.containsKey(node.count)) count2list.put(node.count, new LinkedList<>());
LinkedList<Node> list = count2list.get(node.count);
list.addFirst(node);
return node.v;
}
}
public int[] LFU(int[][] operators, int k) {
LFUCache cache = new LFUCache(k);
List<Integer> list = new ArrayList<>();
for (int[] e : operators) {
if (e[0] == 1) cache.set(e[1], e[2]);
else list.add(cache.get(e[1]));
}
int[] res = new int[list.size()];
for (int i = 0; i < res.length; i++) res[i] = list.get(i);
return res;
}
} 145. 丢棋子问题
思路:动态规划题,dp[i][j]为i个棋子下j次能够辨别的最大n值
class Solution {
public:
int solve(int n, int k) {
if(n < 1) return 0;
if(k == 1)return n;
int t = log2(n) + 1;
if( k >= t)
return t;
vector<int>f(k+1,0);
int cnt=0;
while(f[k] < n) {
++cnt;
for(int i = k;i > 0;--i)
f[i] += f[i-1] + 1;
}
return cnt;
}
}; 

查看11道真题和解析