1、原地移除元素

数组原地移除元素,且空间复杂度为O(1) ,可以直接使用快慢指针

  • 快慢指针都以0 开始增加
  • 快指针直接递增,慢指针在nums[slow]!=nums[fast] 时递增,这样就可以保证慢指针的记录的值仅包含目标值。
  • 返回慢指针,可以看作返回长度为 slow的数组。
  1. public int removeElement(int[] nums, int val) {
  2. int slow = 0, fast;
  3. for (fast = 0; fast < nums.length; fast++) {
  4. if (nums[fast] != val) {
  5. nums[slow] = nums[fast];
  6. slow++;
  7. }
  8. }
  9. return slow;
  10. }

2、反转字符串中的单词

  1. class Solution {
  2. public String reverseWords(String s) {
  3. //直接在字符串首位加空格,方便判断
  4. s = " " + s;
  5. int n = s.length();
  6. StringBuilder sb = new StringBuilder();
  7. int left, right;
  8. //left 一直在往左边走
  9. for (left = n - 1, right = n; left >= 0; left--) {
  10. char ch = s.charAt(left);
  11. //如果遇到空格
  12. if (ch == ' ') {
  13. //将截取的字符串加入到结果中
  14. if (left + 1 < right) {
  15. sb.append(s, left + 1, right).append(' ');
  16. }
  17. //移动右指针
  18. right = left;
  19. }
  20. }
  21. return sb.substring(0, sb.length() - 1);
  22. }
  23. }

3、环形链表

选取快慢指针,快指针走两步,慢指针走一步,如果有环,必定相遇 设链表非环部分长度为 a , 环中部分长度为 b ,f = 2s 且fast总比slow多走n个环,所以 f = s + nb 由上得:f = 2nb s = nb 此时将f 指向头节点,slow 与 fast 同时每轮向前走1 步 当 f 走到a 点时,s = nb+a 此时两指针重合,并指向入口

  1. public ListNode detectCycle(ListNode head) {
  2. ListNode slow = head, fast = slow;
  3. while (slow.next != null && fast.next != null) {
  4. slow = slow.next;
  5. fast = fast.next.next;
  6. if (fast == slow) {
  7. ListNode index1 = head;
  8. ListNode index2 = fast;
  9. while (index2 != index1) {
  10. index2 = index2.next;
  11. index1 = index1.next;
  12. }
  13. return index1;
  14. }
  15. }
  16. return null;
  17. }

4、盛最多水的容器

力扣

从两个方向比较

  1. class Solution {
  2. public int maxArea(int[] height) {
  3. int left = 0, right = height.length - 1;
  4. int max = 0, cur = 0;
  5. while (left < right) {
  6. cur = Math.min(height[left], height[right]) * (right - left);
  7. max = Math.max(cur, max);
  8. if (height[left]>height[right]) right--;
  9. else left++;
  10. }
  11. return max;
  12. }
  13. }

5、三数之和

力扣

主要思想就是先排序,再处理。 对于排序好的数组

  • 如果nums[i] > 0,后面不可能有三个数相加和等于 0 ,直接返回结果。
  • 重复元素跳过,避免出现重复解。
  • 令左指针 L = i+1,右指针R = n-1,当 L < R时,执行循环。
  1. public List<List<Integer>> threeSum(int[] nums) {
  2. List<List<Integer>> res = new ArrayList<>();
  3. ArrayList<Integer> path = new ArrayList<>();
  4. Arrays.sort(nums);
  5. int n = nums.length;
  6. for (int i = 0; i < n; i++) {
  7. if (nums[i]>0) break;
  8. //去除重复解
  9. if (i>0&& nums[i]==nums[i-1]) continue;
  10. int left = i + 1, right = n - 1;
  11. while (left < right) {
  12. if (nums[i] + nums[left] + nums[right] == 0) {
  13. res.add(Arrays.asList(nums[i], nums[left], nums[right]));
  14. //去除重复解,并且移动下标
  15. while (left<right && nums[left]==nums[left+1]) left++;
  16. while (left<right && nums[right]==nums[right-1]) right--;
  17. left++;
  18. right--;
  19. }
  20. // nums[right] 太大,right左移
  21. else if (nums[i] + nums[left] + nums[right] > 0) right--;
  22. //nums[left] 太小,right 右移
  23. else left++;
  24. }
  25. }
  26. return res;
  27. }

6、反转链表

力扣

双指针法: 定义三个指针:pre:存储前一个节点,cur:当前节点,temp:暂存下一个节点

  1. public ListNode reverseList(ListNode head) {
  2. ListNode cur = head;
  3. ListNode pre = null, temp= null;
  4. while (cur != null) {
  5. temp = cur.next;
  6. cur.next = pre;
  7. pre = cur;
  8. cur = temp;
  9. }
  10. return pre;
  11. }

递归:

  1. public ListNode reverseList(ListNode head) {
  2. return reverse(null, head);
  3. }
  4. private ListNode reverse(ListNode prev, ListNode cur) {
  5. if (cur == null) {
  6. return prev;
  7. }
  8. ListNode temp = null;
  9. temp = cur.next;// 先保存下一个节点
  10. cur.next = prev;// 反转
  11. // 更新prev、cur位置
  12. // prev = cur;
  13. // cur = temp;
  14. return reverse(cur, temp);
  15. }

7、两两交换链表中的节点

力扣

双指针: 引入虚拟头节点 prehead,将cur = prehead ,分解为以下几个动作: image.png

  1. public ListNode swapPairs(ListNode head) {
  2. if (head == null || head.next == null) {
  3. return head;
  4. }
  5. ListNode preHead = new ListNode(-1);
  6. preHead.next = head;
  7. ListNode cur = preHead;
  8. //first 存储两两中第一个节点
  9. //secode 存储第二个节点
  10. //temp 存储下一个两两节点中第一个节点
  11. ListNode first, second,temp;
  12. while (cur.next != null && cur.next != null) {
  13. temp = cur.next.next.next;
  14. first = cur.next;
  15. second = first.next;
  16. cur.next = second; //步骤 1
  17. second.next = first; // 步骤 2
  18. first.next = temp; //步骤 3
  19. cur = first;
  20. }
  21. return preHead.next;
  22. }

递归:

···java