在过去一年的时间里, 我在力扣这个平台刷了很多很多的题, 后面就转战牛客, 蓝桥云课等竞赛平台了, 现在我以此篇文章来对力扣刷题做个总结。由于本人水平有限, 仅仅做经验分享 ,但还是希望这篇文章对你有所帮助, (语言的话, 这次就选择C++和Java, 但是本人很少用Java刷题, 因此会在题目中介绍的java的相关方法, 也就当学习了)
学过面向对象都知道, 力扣是采用核心代码模式, 只用去实现对应类中的方法即可, 那我们直接开讲吧(由于题目可能会有很多, 所以就不贴题目, 只分享思路和代码)
知识点讲解参考: Hello算法, Javase 1.8
输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1]一种思路是两层for循环, 另一种就是用哈希表key-value
对于第二种写法, 我们使用哈希表一遍遍历, 一遍存储{nums[i], i}, 顺便去检查哈希表里面是否存在target - nums[i], 如果存在就返回 索引数对
哈希表(hash table)又称散列表,它通过建立键 key 与值 value 之间的映射,实现高效的元素查询。具体而言,我们向哈希表中输入一个键 key ,则可以在O(1)时间内获取对应的值 value
哈希表用法:
/* 初始化哈希表 */
Map<Integer, String> map = new HashMap<>();
/* 添加操作 */
// 在哈希表中添加键值对 (key, value)
map.put(12836, "小哈");
map.put(15937, "小啰");
map.put(16750, "小算");
map.put(13276, "小法");
map.put(10583, "小鸭");
/* 查询操作 */
// 向哈希表中输入键 key ,得到值 value
String name = map.get(15937);
/* 删除操作 */
// 在哈希表中删除键值对 (key, value)
map.remove(10583);
/*Returns true if this map contains a mapping for the specified key.*/
map.containKey(12836)
C++:
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int,int> mp; int idx=-1;
for(auto& x:nums){
idx++;
if(mp.find(target-x)!=mp.end()){
return {mp[target-x],idx};
}
mp[x]=idx;
}
return {};
}
};
JAVA:
class Solution {
public int[] twoSum(int[] nums, int target) {
Map<Integer,Integer> mp=new HashMap<>();
for(int i=0;i<nums.length;i++){
int tmp=target-nums[i];
if(mp.containsKey(tmp)){
return new int[]{mp.get(tmp),i};
}
mp.put(nums[i],i);
}
return new int[0];
}
}
在链表的首位添加一个节点
链表(linked list)是一种线性数据结构,其中的每个元素都是一个节点对象,各个节点通过“引用”相连接。引用记录了下一个节点的内存地址,通过它可以从当前节点访问到下一个节点
链表的设计使得各个节点可以分散存储在内存各处,它们的内存地址无须连续JAVA里面是没有指针, 只有引用
链表用法:
/* 链表节点类 */
class ListNode {
int val; // 节点值
ListNode next; // 指向下一节点的引用
ListNode(int x) { val = x; } // 构造函数
}
/* 初始化链表 1 -> 3 -> 2 -> 5 -> 4 */
// 初始化各个节点
ListNode n0 = new ListNode(1);
ListNode n1 = new ListNode(3);
ListNode n2 = new ListNode(2);
ListNode n3 = new ListNode(5);
ListNode n4 = new ListNode(4);
// 构建节点之间的引用
n0.next = n1;
n1.next = n2;
n2.next = n3;
n3.next = n4;
C++:
class Solution {
public:
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
ListNode *v = new ListNode(0), *cur = v;
int sum = 0;
while (l1 || l2 || sum) {
if (l1)
sum += l1->val, l1 = l1->next;
if (l2)
sum += l2->val, l2 = l2->next;
cur->next = new ListNode(sum % 10);
cur = cur->next;
sum /= 10;
}
return v->next;
}
};
Java:
class Solution {
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
ListNode v = new ListNode(0);
ListNode cur = v;
int carry = 0;
while (l1 != null || l2 != null || carry != 0) {
int sum = carry;
if (l1 != null) {
sum += l1.val;
l1 = l1.next;
}
if (l2 != null) {
sum += l2.val;
l2 = l2.next;
}
cur.next = new ListNode(sum % 10);
cur = cur.next;
carry = sum / 10;
}
return v.next;
}
}
输入: s = "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。滑动窗口维护:
使用两个指针l和r表示窗口的左右边界
l指向当前无重复子串的起始位置
r不断向右移动扩展窗口
核心逻辑:
每当r向右移动一位,检查新字符s[r]是否在窗口[l,r-1]中出现过
如果出现过(f=1),就将l移动到重复字符的下一个位置(j+1)
如果没出现过(f=0),就更新最大长度mx可以使用哈希表进行优化
C++:
class Solution {
public:
int lengthOfLongestSubstring(string s) {
unordered_map<int,int> mp;
int L=0, mx_len=0, n=s.size();
for(int r=0;r<n;r++){
char c=s[r];
if(mp.find(c)!=mp.end()&&mp[c]>=L){
L=mp[c]+1;
}
mp[c]=r;
mx_len=max(mx_len,r-L+1);
}
return mx_len;
}
};
Java:
class Solution {
public int lengthOfLongestSubstring(String s) {
Map<Character, Integer> mp = new HashMap<>();
int L = 0, mx_len = 0, n = s.length();
for (int r = 0; r < n; r++) {
char c = s.charAt(r);
if (mp.containsKey(c) && mp.get(c) >= L) {
L = mp.get(c) + 1;
}
mp.put(c, r); //维护当前字符的右边界
mx_len = Math.max(mx_len, r - L + 1);
}
return mx_len;
}
}
输入:s = "babad"
输出:"bab"
解释:"aba" 同样是符合题意的答案。定义一个函数 dfs(i, j) 来判断 s[i..j] 是否为回文串,并用记忆化表 dp[i][j] 来存储中间结果。
然后我们遍历所有可能的子串 s[i..j],当 dfs(i, j) 为真时,尝试更新最长的回文子串
class Solution {
private Boolean[][] memo;
public String longestPalindrome(String s) {
int n = s.length();
memo = new Boolean[n][n];
int mx_len = 0;
int st = 0;
for (int i = 0; i < n; ++i) {
for (int j = i; j < n; ++j) {
if (dfs(s, i, j)) {
if (j - i + 1 > mx_len) {
mx_len = j - i + 1;
st = i;
}
}
}
}
return s.substring(st, st + mx_len);
}
private boolean dfs(String s, int i, int j) {
if (i >= j) return true;
if (memo[i][j] != null) return memo[i][j];
if (s.charAt(i) != s.charAt(j)) {
memo[i][j] = false;
} else {
memo[i][j] = dfs(s, i + 1, j - 1);
}
return memo[i][j];
}
}
区分:StringBuilder是线程不安全的,StringBuffer是线程安全的(所有方法都用 synchronized 修饰),前者在单线程中使用, 后者在多线程中使用, 前者性能更高, 后者确保线程安全
class Solution {
public String convert(String s, int numRows) {
if(numRows==1) return s;
StringBuilder[] r=new StringBuilder[numRows];
for(int i=0;i<numRows;i++){
r[i]=new StringBuilder();
}
boolean f=false;
int cur_r=0;
for(char c:s.toCharArray()){
r[cur_r].append(c);
if(cur_r==0||cur_r==numRows-1){
f=!f;
}
cur_r+=f?1:-1;
}
StringBuilder res=new StringBuilder();
for(StringBuilder x:r){
res.append(x);
}
return res.toString();
}
}
class Solution {
public:
string convert(string s, int len) {
if(len==1) return s;
vector<string> ans(len);
bool f=false; int n=s.size();
int row=0;
for(int i=0;i<n;i++){
ans[row]+=s[i];
if(row==0||row==len-1) f=!f;
row+=f?1:-1;
}
string res="";
for(auto& x:ans) res+=x;
return res;
}
};
解题思路:直接翻转即可,注意不要超过int
class Solution {
public:
int reverse(int x){
long long reversed = 0;
while (x != 0) {
int digit = x % 10;
reversed = reversed * 10 + digit;
if (reversed > INT_MAX || reversed < INT_MIN){
return 0;
}
x /= 10;
}
return reversed;
}
};
class Solution {
public:
int reverse(int x){
long long reversed = 0;
while (x != 0) {
int digit = x % 10;
reversed = reversed * 10 + digit;
if (reversed > INT_MAX || reversed < INT_MIN){
return 0;
}
x /= 10;
}
return reversed;
}
};
解题思路:类似于C++中的stoi函数
class Solution {
public int myAtoi(String s) {
long ans=0;
int start=0,n=s.length();
while(start<n&&s.charAt(start)==' '){
start++;
}
if(start==n) return 0;
int f=1;
if(s.charAt(start)=='-'){
f=-1;
start++;
}else if(s.charAt(start)=='+'){
start++;
}
for(int i=start;i<n&&Character.isDigit(s.charAt(i));i++){
ans=ans*10+f*(s.charAt(i)-'0');
if(ans>0&&ans>Integer.MAX_VALUE){
return Integer.MAX_VALUE;
}
if(ans<0&&ans<Integer.MIN_VALUE){
return Integer.MIN_VALUE;
}
}
return (int)ans;
}
}
class Solution {
public:
int myAtoi(string s) {
long long ans=0;
int start=0;
while(start<s.length() && s[start]==' ') start++;
if(start==s.length()) return 0;
int sign=1;
if(s[start]=='-') sign=-1,start++;
else if(s[start]=='+') start++;
for(int i=start;i<s.length()&&isdigit(s[i]);i++)
{
ans=ans*10+sign*(s[i]-'0');
if(ans>0&&ans>=INT_MAX) return INT_MAX;
if(ans<0&&ans<=INT_MIN) return INT_MIN;
}
return ans;
}
};
回文数判断
class Solution {
public boolean isPalindrome(int x) {
if(x<0) return false;
long tmp=x,res=0;
while(tmp>0){
res=res*10+tmp%10;
tmp/=10;
}
if(res==x) return true;
return false;
}
}
class Solution {
public:
bool isPalindrome(int x) {
if (x < 0){
return false;
}
long long m = x;
long long i = 0;
while (m) {
i = i * 10 + m % 10;
m /= 10;
}
if (i == x){
return true;
}else{
return false;
}
}
};
class Solution {
public int maxArea(int[] height) {
int ans=0;
int left=0,right=height.length-1;
while(left<right){
ans=Math.max(ans,Math.min(height[left],height[right])*(right-left));
if(height[left]<height[right]) left++;
else right--;
}
return ans;
}
}
class Solution {
public:
int maxArea(vector<int>& height) {
int ans=0;
int l=0,r=height.size()-1;
while(l<r)
{
ans=max(ans,min(height[l],height[r])*(r-l));
if(height[l]<height[r]) l++;
else r--;
}
return ans;
}
};