哈希
两数之和
package leetcode.editor.cn;
import java.util.HashMap;
class twoSum{
//2024-05-11 10:49:42
//两数之和
//编号:[1]
public static void main(String[] args) {
Solution solution = new twoSum().new Solution();
// TO TEST
}
//leetcode submit region begin(Prohibit modification and deletion)
class Solution {
public int[] twoSum(int[] nums, int target) {
HashMap<Integer,Integer> mp = new HashMap();
for (int i = 0; i < nums.length; i++) {
if(mp.containsKey(target - nums[i])){
return new int[]{mp.get(target - nums[i] ), i};
}
mp.put(nums[i],i);
}
return new int[]{};
}
}
//leetcode submit region end(Prohibit modification and deletion)
}
字母异位词
//leetcode submit region begin(Prohibit modification and deletion)
class Solution {
public List<List<String>> groupAnagrams(String[] strs) {
HashMap<String,List<String>> mp = new HashMap<>();
for (String str : strs) {//eat
int[] count = new int[26];
for (int i = 0; i < str.length(); i++) {
count[str.charAt(i) - 'a']++;
}//[1 1 1]
StringBuffer sb = new StringBuffer();
for (int i = 0; i < 26; i++) {
if(count[i] != 0){
sb.append((char) i + 'a');
sb.append(i);
}
}//a1e1t1
String key = sb.toString();
List<String> list = mp.getOrDefault(key,new ArrayList<>());
list.add(str);
mp.put(key,list);
}
return new ArrayList<List<String>>(mp.values());
}
}
//leetcode submit region end(Prohibit modification and deletion)
}
最长连续序列
class Solution {
public int longestConsecutive(int[] nums) {
//定义HashSet,作为去重
HashSet<Integer> set = new HashSet<>();
//遍历nums,赋值给set
for (Integer num : nums) {
set.add(num);
}
//定义最终结果
int result = 0;
//把每个点都作为起始点遍历
for (Integer num : set) {
//记录每次的长度,用于和最终结果比较
int longStream = 0;
//while循环往后找,记录次数
while(set.contains(num)){
longStream++;
num++;
}
//每次都记录最大长度
result = Math.max(result,longStream);
}
return result;
}
}
双指针
移动零
class Solution {
public void moveZeroes(int[] nums) {
if(nums.length == 0){
return;
}
int j = 0;
for (int i = 0; i < nums.length; i++) {
if(nums[i] != 0){
nums[j++] = nums[i];
}
}
for (int i = j; i < nums.length; i++) {
nums[i] = 0;
}
}
}
盛最多水的容器
class Solution {
public int maxArea(int[] height) {
int left = 0;
int right = height.length - 1;
int res = 0;
while(left < right){
res = height[left] < height[right]?
Math.max(res,(right - left) * (height[left++])):
Math.max(res,(right - left) * (height[right--]));
}
return res;
}
}
三数之和
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
//构造二维数组
List<List<Integer>> ans = new ArrayList<>();
int len = nums.length;
//极端情况(数组是空或者长度不够3个)
if(nums == null || len < 3) return ans;
//对数组进行排序
Arrays.sort(nums);//[-4,-1,-1,0,1,2]
for(int i = 0; i < len ; i++){
//极端情况(数组均大于0)
if(nums[i] > 0) break;
//特殊情况-给a去重(i的值等于i-1的值)
if(i>0 && nums[i] == nums[i-1]) continue;
int left = i+1;
int right = nums.length - 1;
while(left < right){
int sum = nums[i] + nums[left] + nums[right];
//收获结果
if(sum == 0){
//把这个包含三个值的固定列表结果放到ans中
ans.add(Arrays.asList(nums[i],nums[left],nums[right]));
//给bc处理重复元素,如[-3 1 1 1 2 2]
while(left < right && nums[left] == nums[left + 1]) left++;
while(left > right && nums[right] == nums[right - 1]) right--;
//继续向后查找下一组元素
left++;
right--;
}
else if (sum < 0) left++;
else if (sum > 0) right--;
}
}
return ans;
}
}
滑动窗口
无重复字符的最长子串
class Solution {
public int lengthOfLongestSubstring(String s) {
HashMap<Character, Integer> mp = new HashMap<>();
int res = 0;
int left = 0;
for (int right = 0; right < s.length(); right++) {
if (mp.containsKey(s.charAt(right))) {
left = Math.max(left,mp.get(s.charAt(right)) + 1);
}
mp.put(s.charAt(right), right);
res = Math.max(res, right - left + 1);
}
return res;
}
}
找到字符串中所有字母移位词
class Solution {
public List<Integer> findAnagrams(String s, String p) {
List<Integer> list = new ArrayList<>();
//极端情况判断
if(s.length() < p.length()) return list;
int plen = p.length();
int slen = s.length();
//创建两个数组作为次数的记录
int[] scount = new int[26];
int[] pcount = new int[26];
//只遍历前p个元素,统计次数
for (int i = 0; i < plen; i++) {
//统计a出现次数并++,如 a 字母中为 1 b = 2
++scount[s.charAt(i) - 'a'];
++pcount[p.charAt(i) - 'a'];
}
//如果完全一致代表滑块重叠,需记录
if(Arrays.equals(scount,pcount)){
list.add(0);
}
//移动滑块
for (int i = 0; i < s.length() - plen; i++) {
//因为向右移动滑块,所以要剔除左边第一个字母
--scount[s.charAt(i) - 'a'];
//右进一个字母
++scount[s.charAt(i+plen) - 'a'];
if(Arrays.equals(scount,pcount)){
list.add(i+1);
}
}
return list;
}
}
普通数组
和为K的子数组
class Solution {
public int subarraySum(int[] nums, int k) {
int count = 0;
for(int end=0;end<nums.length;end++){
int sum = 0;
for(int start =end;start>=0;start--){
sum += nums[start];
if(sum == k){
count++;
}
}
}
return count;
}
}
合并数组
//[[2,6],[1,3],[8,10],[15,18]]
if(intervals.length == 0) return new int[][]{};
//对二维数组的第一个元素进行排序
Arrays.sort(intervals, new Comparator<int[]>() {
@Override
public int compare(int[] o1, int[] o2) {
return o1[0] - o2[0];
}
});//[,[1,3][2,6],[8,10],[15,18]]
//创建一个二维数组用来存储结果
List<int[]> merged = new ArrayList<>();
for (int i = 0; i < intervals.length; i++) {
int left = intervals[i][0];//1
int right = intervals[i][1];//3
if(merged.size() == 0 || merged.get(merged.size() - 1)[1] < left){
merged.add(new int[]{left,right});
}else {
merged.get(merged.size() - 1)[1] = Math.max(merged.get(merged.size() - 1)[1],right);
}
}
return merged.toArray(new int[merged.size()][]);
轮转数组
class Solution {
public void rotate(int[] nums, int k) {
int[] newarr = new int[nums.length];
for(int i=0;i<nums.length;i++){
newarr[(i+k)%nums.length] = nums[i];
}
System.arraycopy(newarr,0,nums,0,nums.length);
}
}
最大子数组和
class Solution {
public int maxSubArray(int[] nums) {
if(nums.length == 0) return 0;
int[] dp = new int[nums.length];
dp[0] = nums[0];
//易错点
int MaxLength = dp[0];
for (int i = 1; i < nums.length; i++) {
if(dp[i-1] > 0){
dp[i] = dp[i-1] + nums[i];
}else {
dp[i] = nums[i];
}
MaxLength = Math.max(MaxLength,dp[i]);
}
return MaxLength;
}
}
除自身以外数组的乘积
class Solution {
public int[] productExceptSelf(int[] nums) {
int length = nums.length;
int[] left = new int[length];
int[] right = new int[length];
int[] answer = new int[length];
//计算左边的乘积
left[0] = 1;
for (int i = 1; i < length; i++) {
left[i] = nums[i-1] * left[i-1];
}
//计算右边的乘积
right[length - 1] = 1;
for (int i = length - 2; i >= 0; i--) {
right[i] = nums[i+1] * right[i+1];
}
for (int i = 0; i < length; i++) {
answer[i] = left[i] * right[i];
}
return answer;
}
}
矩阵
矩阵置零
class Solution {
public void setZeroes(int[][] matrix) {
//获取矩阵的行的个数
int m = matrix.length;
//获取矩阵的列的个数
int n = matrix[0].length;
//用数组来记录哪些行和列中包含0
boolean[] row = new boolean[m];
boolean[] col = new boolean[n];
//双层循环遍历,如果是零,那么把row和col都置为true
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if(matrix[i][j] == 0){
row[i] = col[j] = true;
}
}
}
//再次双层循环遍历,如果row[i] 或者 col[j] 是0,那么就把matrix[i][j]置为0
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if(row[i] || col[j]){
matrix[i][j] = 0;
}
}
}
}
}
螺旋矩阵
class Solution {
public List<Integer> spiralOrder(int[][] matrix) {
List<Integer> list = new ArrayList<>();
//极端情况判断
if(matrix.length == 0 || matrix[0].length == 0){
return list;
}
int rows = matrix.length;
int columns = matrix[0].length;
//数组用作是否跳转方向的判断
boolean[][] visited = new boolean[rows][columns];
int total = rows * columns;
int row = 0;
int column = 0;
//数组用作调整方向
int[][] directions = {{0,1},{1,0},{0,-1},{-1,0}};
//基础方向是向右
int directionIndex = 0;
for (int i = 0; i < total; i++) {
list.add(matrix[row][column]);
visited[row][column] = true;
//提前看下一行、下一列的值
int nextRow = row + directions[directionIndex][0];
int nextColumn = column + directions[directionIndex][1];
//根据下一行下一列的值是否超过或等于边界 判断是否调整方向
if(nextRow < 0 || nextRow >= rows || nextColumn < 0 || nextColumn >= columns || visited[nextRow][nextColumn]){
directionIndex = (directionIndex + 1 ) % 4;
}
//向后遍历row++ column++
row += directions[directionIndex][0];
column += directions[directionIndex][1];
}
return list;
}
}
旋转图像
class Solution {
public void rotate(int[][] matrix) {
int[][] matrix_new = new int[matrix.length][matrix.length];
for(int i = 0;i<matrix.length;i++){
for(int j = 0;j<matrix.length;j++){
matrix_new[j][matrix.length-i-1] = matrix[i][j];
}
}
for(int i =0;i<matrix.length;i++){
for(int j = 0 ;j<matrix.length;j++){
matrix[i][j] = matrix_new[i][j];
}
}
}
}
搜索二维矩阵 II
class Solution {
public boolean searchMatrix(int[][] matrix, int target) {
for (int[] row : matrix) {
int index = search(row,target);
if(index >= 0){
return true;
}
}
return false;
}
public int search(int[] nums , int target){
int low = 0;
int high = nums.length - 1;
while(low <= high){
int mid = (high + low) / 2;
int num = nums[mid];
if(num == target){
return nums[mid];
}else if (num > target){
high = mid - 1;
}else
low = mid + 1;
}
return -1 ;
}
}
链表
相交链表
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
HashSet<ListNode> set = new HashSet<ListNode>();
ListNode list1 = headA;
ListNode list2 = headB;
while(list1 != null){
set.add(list1);
list1 = list1.next;
}
while(list2 != null){
if(set.contains(list2)){
return list2;
}
list2 = list2.next;
}
return null;
}
}
反转链表
class Solution {
public ListNode reverseList(ListNode head) {
Stack<ListNode> stack = new Stack<ListNode>();
ListNode list = head;
while(list != null){
stack.push(list);
list = list.next;
}
ListNode list2 = stack.pop();//第一个元素用来移动
ListNode nummy = list2;//用来返回最终结果
while(!stack.isEmpty()){
ListNode tempNode = stack.pop();
list2.next = tempNode;
list2 = list2.next;
}
list2.next = null;
return nummy;
}
}
回文链表
class Solution {
public boolean isPalindrome(ListNode head) {
ArrayList<ListNode> nums = new ArrayList<ListNode>();
while(head != null){
nums.add(head);
head = head.next;
}
for (int i = 0; i < nums.size(); i++) {
if(nums.get(i).val != nums.get(nums.size() - i -1).val){
return false;
}
}
return true;
}
}
环形链表
public class Solution {
public boolean hasCycle(ListNode head) {
HashSet<ListNode> set = new HashSet<>();
while(head!=null){
//set.add方法会返回一个布尔类型的值
//如果添加失败,代表有重复-->有环
if(!set.add(head)) {
return true;
}
head = head.next;
}
return false;
}
}
环形链表2
public class Solution {
public ListNode detectCycle(ListNode head) {
HashSet<ListNode> set = new HashSet<ListNode>();
while (head != null){
if(set.contains(head)){
return head;
}
set.add(head);
head = head.next;
}
return null;
}
}
合并两个有序链表
if(list1 == null){
return list2;
}
if(list2 == null){
return list1;
}
ListNode newlist = new ListNode(0);
ListNode bak = newlist;
// if(list1.val <= list2.val){newlist.next = list1;list1 = list1.next;}
// if(list1.val > list2.val){newlist.next = list2;list2 = list2.next;}
while(list1 != null && list2 != null){
if(list1.val <= list2.val){
bak.next = list1;
list1 = list1.next;
}else{
bak.next = list2;
list2 = list2.next;
}
bak = bak.next;
}
if(list1 !=null){
bak.next = list1;
}
if(list2 != null){
bak.next = list2;
}
return newlist.next;
两数相加
class Solution {
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
//生成一个新的链表
ListNode pre = new ListNode(0);
ListNode cur = pre;
int carry = 0;//位数
while( l1!=null || l2!=null){
int x = l1 == null? 0: l1.val;
int y = l2 == null? 0: l2.val;
int sum = x + y + carry;
carry = sum/10;//获取位
sum = sum % 10;//获取新链表的和
cur.next = new ListNode(sum);//把新链表的和放到新的链表中
cur = cur.next;
if(l1 != null)
l1 = l1.next;
if(l2 != null)
l2 = l2.next;
}
if(carry == 1){
cur.next = new ListNode(carry);
}
return pre.next;
}
}
删除链表的倒数第N个结点
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
//1.极端情况判断
if(head == null){return null;}
//2.关键变量声明
//声明头节点
ListNode dummy = new ListNode(0);
dummy.next = head;
ListNode cur = dummy;
//声明链表长度
int length = Solution.LengthSearch(head);
//3.循环遍历
for (int i = 1; i < length - n + 1; i++) {
cur = cur.next;//找到了该元素
}
cur.next = cur.next.next;
return dummy.next;
}
public static int LengthSearch(ListNode head){
int length = 0;
while (head != null){
length++;
head = head.next;
}
return length;
}
}
两两交换链表中的节点
class Solution {
public ListNode swapPairs(ListNode head) {
if(head == null || head.next == null){
return head;
}
ListNode newHead = head.next;
head.next = swapPairs(newHead.next);
newHead.next = head;
return newHead;
}
}
随机链表的复制
class Solution {
public Node copyRandomList(Node head) {
//1.极端情况判断
if(head == null){
return null;
}
//2.关键变量定义
HashMap<Node,Node> map = new HashMap<Node, Node>();
//3.循环遍历
//内存中创建全新的Node(深拷贝)
for(Node curr = head; curr != null;curr = curr.next){
map.put(curr , new Node(curr.val));
}
for(Node curr = head; curr != null;curr = curr.next){
map.get(curr).next = map.get(curr.next);
map.get(curr).random = map.get(curr.random);
}
//4.返回结果
return map.get(head);
}
}