- 双指针
- 344.反转字符串">344.反转字符串
- 面试题16.24.数对和(例题1)">面试题16.24.数对和(例题1)
- 1.两数之和">1.两数之和
- 15.三数之和">15.三数之和
- 剑指 Offer 21.调整数组顺序使奇数位于偶数前面">剑指 Offer 21.调整数组顺序使奇数位于偶数前面
- 75.颜色分类">75.颜色分类
- 283.移动零已排序未排序指针(例题2)">283.移动零已排序未排序指针(例题2)
- 面试题 16.06.最小差 类似合并两个有序数组(例题3)">面试题 16.06.最小差 类似合并两个有序数组(例题3)
- 面试题 17.11.单词距离 类似合并两个有序数组">面试题 17.11.单词距离 类似合并两个有序数组
- 滑动窗口
- 前缀后缀统计
- 位运算
- 191.位1的个数(例题1)">191.位1的个数(例题1)
- 461.汉明距离(例题2)">461.汉明距离(例题2)
- 面试题05.06.整数转换">面试题05.06.整数转换
- 面试题05.07.配对交换">面试题05.07.配对交换
- 面试题05.01.插入">面试题05.01.插入
- 面试题17.04.消失的数字">面试题17.04.消失的数字
- 剑指Offer 56 - I.数组中数字出现的次数">剑指Offer 56 - I.数组中数字出现的次数
- 剑指Offer 56 - II.数组中数字出现的次数II">剑指Offer 56 - II.数组中数字出现的次数II
- 面试题16.01.交换数字">面试题16.01.交换数字
- 231. 2的幂">231. 2的幂
双指针
344.反转字符串
class Solution {public void reverseString(char[] s) {int start = 0, end = s.length - 1;while(start < end) {char temp = s[start];s[start] = s[end];s[end] = temp;start++;end--;}}}
面试题16.24.数对和(例题1)
class Solution {public List<List<Integer>> pairSums(int[] nums, int target) {List<List<Integer>> result = new ArrayList<>();Arrays.sort(nums);int start = 0, end = nums.length - 1;while(start < end) {int sum = nums[start] + nums[end];if(sum == target) {List<Integer> list = new ArrayList<>();list.add(nums[start]);list.add(nums[end]);result.add(list);start++;end--;}else if(sum > target) {end--;} else {start++;}}return result;}}
1.两数之和
class Solution {public int[] twoSum(int[] nums, int target) {int start = 0, end = nums.length - 1;int[] temp = Arrays.copyOf(nums, nums.length);Arrays.sort(temp);int[] result = new int[] {-1, -1};while(start < end) {int sum = temp[start] + temp[end];if(target == sum) {break;} else if(target > sum) {start++;} else {end--;}}for(int i = 0; i < nums.length; i++) {if(temp[start] == nums[i] && result[0] == -1) {result[0] = i;continue;}if(temp[end] == nums[i] && result[1] == -1) {result[1] = i;}}return result;}}
15.三数之和
class Solution {public List<List<Integer>> threeSum(int[] nums) {List<List<Integer>> reslut = new ArrayList<>();int n = nums.length;Arrays.sort(nums);// 边界条件if(n < 3 || nums[0] > 0 || nums[n - 1] < 0) {return new ArrayList<>();}for(int i = 0; i < n; i++) {// 过滤重复数据if(i != 0 && nums[i] == nums[i - 1]) {continue;}int target = -nums[i];int head = i + 1, tail = n - 1;while(head < tail) {int sum = nums[head] + nums[tail];if(sum == target) {List<Integer> list = new ArrayList<>();list.add(nums[i]);list.add(nums[head]);list.add(nums[tail]);reslut.add(list);head++;tail--;// 过滤重复数据while(head < tail && nums[head] == nums[head - 1]) {head++;}// 过滤重复数据while(head < tail && nums[tail] == nums[tail + 1]) {tail--;}} else if (sum < target) {head++;} else {tail--;}}}return reslut;}}
剑指 Offer 21.调整数组顺序使奇数位于偶数前面
首尾指针
class Solution {public int[] exchange(int[] nums) {// 首尾指针int head = 0, tail = nums.length - 1;while(head < tail) {while(head < tail && (nums[head] & 1) == 1) {head++;}while(head < tail && (nums[tail] & 1) != 1) {tail--;}if(head < tail) {int temp = nums[head];nums[head] = nums[tail];nums[tail] = temp;}}return nums;}}
快慢指针
class Solution {public int[] exchange(int[] nums) {int slow = 0, fast = 0;while(fast < nums.length) {if((nums[fast] & 1) == 1) {int temp = nums[slow];nums[slow] = nums[fast];nums[fast] = temp;slow++;}fast++;}return nums;}}
75.颜色分类
单指针解法
class Solution {public void sortColors(int[] nums) {// 单指针解法int idx = 0;// 先把0移至数组前面for(int i = 0; i < nums.length; i++) {if(nums[i] == 0) {swap(nums, idx, i);idx++;}}// 然后把1移至最后一个0的后面for(int i = idx; i < nums.length; i++) {if(nums[i] == 1) {swap(nums, idx, i);idx++;}}}private void swap(int[] nums, int s, int t) {int temp = nums[s];nums[s] = nums[t];nums[t] = temp;}}
单数组上前后指针(首尾指针)-solution1
class Solution {public void sortColors(int[] nums) {int head = 0, tail = nums.length - 1;// 先交换0head = sort(nums, head, 0);sort(nums, head, 1);}private int sort(int[] nums, int head, int color) {int tail = nums.length - 1;while(head <= tail) {while(head <= tail && nums[head] == color) {head++;}while(head <= tail && nums[tail] != color) {tail--;}if(head < tail) {swap(nums, head, tail);head++;tail--;}}return head;}private void swap(int[] nums, int s, int t) {int temp = nums[s];nums[s] = nums[t];nums[t] = temp;}}
单数组上前后指针(首尾指针)-solution2
class Solution {public void sortColors(int[] nums) {int head = 0, tail = nums.length - 1, size = nums.length;// 双指针解法for(int i = 0; i < size; i++) {while(i < tail && nums[i] == 2) {swap(nums, i, tail);tail--;}if(nums[i] == 0) {swap(nums, i, head);head++;}}}private void swap(int[] nums, int s, int t) {int temp = nums[s];nums[s] = nums[t];nums[t] = temp;}}
283.移动零已排序未排序指针(例题2)
快慢指针
class Solution {public void moveZeroes(int[] nums) {// 快慢指针int fast = 0, slow = 0, size = nums.length;while(fast < nums.length) {while(slow < size && nums[slow] != 0) {slow++;}fast = slow + 1;while(fast < size && nums[fast] == 0) {fast++;}if(fast < size) {swap(nums, slow, fast);slow++;fast++;}}}private void swap(int[] nums, int s, int t) {int temp = nums[s];nums[s] = nums[t];nums[t] = temp;}}
借鉴快排的分区思想-区间指针
class Solution {public void moveZeroes(int[] nums) {int size = nums.length, sorted = 0;for(int i = 0; i < size; i++) {if(nums[i] != 0) {swap(nums, sorted, i);sorted++;}}}private void swap(int[] nums, int s, int t) {int temp = nums[s];nums[s] = nums[t];nums[t] = temp;}}
面试题 16.06.最小差 类似合并两个有序数组(例题3)
区间指针
class Solution {public int smallestDifference(int[] a, int[] b) {// 排序Arrays.sort(a);Arrays.sort(b);long min = Long.MAX_VALUE;int s1 = 0, s2 = 0;while(s1 < a.length && s2 < b.length) {if(a[s1] < b[s2]) {min = Math.min(min, (long) b[s2] - a[s1]);s1++;} else {min = Math.min(min, (long) a[s1] - b[s2]);s2++;}}return (int) min;}}
面试题 17.11.单词距离 类似合并两个有序数组
区间指针
class Solution {public int findClosest(String[] words, String word1, String word2) {int size = words.length;int i = 0, j = 0, shortestDist = Integer.MAX_VALUE;while(i < size && !words[i].equals(word1)) {i++;}while(j < size && !words[j].equals(word2)) {j++;}while(i < size && j < size) {if(i > j) {shortestDist = Math.min(shortestDist, i - j);j++;while(j < size && !words[j].equals(word2)) {j++;}} else {shortestDist = Math.min(shortestDist, j - i);i++;while(i < size && !words[i].equals(word1)) {i++;}}}return shortestDist;}}
滑动窗口
剑指Offer 57 - II.和为s的连续正数序列(例题1)
滑动窗口-双指针
class Solution {public int[][] findContinuousSequence(int target) {int start = 1, end = 2, sum = 3;if(target < 2) {return new int[0][0];}List<int[]> list = new ArrayList<>();while(end < target) {if(sum == target) {int size = end - start + 1;int[] temp = new int[size];int t = start;for(int i = 0; i < size; i++) {temp[i] = t++;}list.add(temp);sum -= start;start++;end++;sum += end;} else if(sum < target) {end++;sum += end;} else {sum -= start;start++;}}return list.toArray(new int[list.size()][]);}}
滑动窗口-双指针-代码简化
class Solution {public int[][] findContinuousSequence(int target) {int s = 1, e = 2;if(target < 2) {return new int[0][0];}List<int[]> result = new ArrayList<>();while(s < e) {// 等差数列求和 = (首项 + 末项) * 项数 / 2int sum = (s + e) * (e - s + 1) / 2;if(sum == target) {int[] res = new int[e - s + 1];for(int i = s; i <= e; i++) {res[i - s] = i;}result.add(res);s++;e++;} else if (sum < target) {e++;} else {s++;}}return result.toArray(new int[result.size()][]);}}
剑指Offer 48.最长不含重复字符的子字符串(例题2)
class Solution {public int lengthOfLongestSubstring(String s) {// 维护一个不重复字符的集合Set<Character> set = new HashSet<>();int l = 0, r = 0, max = Integer.MIN_VALUE;while(r < s.length()) {char c = s.charAt(r);if(set.contains(c)) {max = Math.max(max, set.size());while(set.contains(c)) {set.remove(s.charAt(l));l++;}}set.add(c);r++;}return Math.max(max, set.size());}}
438.找到字符串中所有字母异位词
滑动窗口
class Solution {public List<Integer> findAnagrams(String s, String p) {int size = p.length(), l = 0, r = size - 1;List<Integer> result = new ArrayList<>();int[] map = new int[27];// 初始化异位词的mapfor(int i = 0; i < size; i++) {map[p.charAt(i) - 'a']++;}while(r < s.length()) {if(compare(l, r, s, map)) {result.add(l);}l++;r++;}return result;}boolean compare(int l, int r, String s, int[] map) {int[] temp = new int[27];for(int i = l; i <= r; i++) {temp[s.charAt(i) - 'a']++;}for(int i = 0; i < map.length; i++) {if(temp[i] != map[i]) {return false;}}return true;}}
滑动窗口-代码优化
class Solution {public List<Integer> findAnagrams(String s, String p) {if(s.length() < p.length()) {return new ArrayList<>();}int pLen = p.length();List<Integer> result = new ArrayList<>();int[] map = new int[27];int[] temp = new int[27];// 初始化异位词的mapfor(int i = 0; i < pLen; i++) {map[p.charAt(i) - 'a']++;temp[s.charAt(i) - 'a']++;}if(compare(temp, map)) {result.add(0);}for(int i = pLen; i < s.length(); i++) {temp[s.charAt(i - pLen) - 'a']--;temp[s.charAt(i) - 'a']++;if(compare(temp, map)) {result.add(i - pLen + 1);}}return result;}boolean compare(int[] temp, int[] map) {for(int i = 0; i < map.length; i++) {if(temp[i] != map[i]) {return false;}}return true;}}
76.最小覆盖子串
前缀后缀统计
121.买卖股票的最佳时机(例题1)
后缀和
class Solution {public int maxProfit(int[] prices) {int n = prices.length;// 定义后缀和数组,max[i] 表示第 i+1 ~ n 天之间的最大值int[] max = new int[n];int curMaX = 0;// 计算后缀和for(int i = n - 1; i >= 0; i--) {max[i] = curMaX;curMaX = Math.max(prices[i], curMaX);}int result = 0;for(int i = 0; i < n - 1; i++) {result = Math.max(result, max[i] - prices[i]);}return result;}}
单次遍历
解题思路:
遍历数组,记录历史最低点,然后考虑如果我是在历史最低点买进的,那么我今天卖出能赚多少钱?当考虑完所有天数之时,我们就得到了最好的答案。
class Solution {public int maxProfit(int[] prices) {int minPrices = Integer.MAX_VALUE, maxProfit = Integer.MIN_VALUE;for(int i = 0; i < prices.length; i++) {minPrices = Math.min(minPrices, prices[i]);maxProfit = Math.max(maxProfit, prices[i] - minPrices);}return maxProfit;}}
238.除自身以外数组的乘积(例题2)
前缀积和后缀积
解题思路:
假设 leftProduct[i] 表示 nums[0 ~ i-1] 的元素乘积,rightProduct[i] 表示 nums[i+1 ~ n] 的元素乘积,那么 leftProduct[i] * rightProduct[i] 则表示除 nums[i] 之外其余各元素的乘积。
由于题目限制,空间复杂度要在 O(n),那么可以重用结果集来做。
class Solution {public int[] productExceptSelf(int[] nums) {int n = nums.length;int[] result = new int[n];int leftProduct = 1;for(int i = 0; i < n; i++) {result[i] = leftProduct;leftProduct *= nums[i];}int rightProduct = 1;for(int i = n - 1; i >= 0; i--) {result[i] = rightProduct * result[i];rightProduct *= nums[i];}return result;}}
面试题05.03.翻转数位
位运算
class Solution {public int reverseBits(int num) {int cur = 0, res = 1, insert = 0;for(int i = 0; i < 32; i++) {if((num & 1) == 1) {cur++;insert++;} else {insert = cur + 1;cur = 0;}res = Math.max(res, insert);num = num >> 1;}return res;}}
42. 接雨水
暴力破解
class Solution {public int trap(int[] height) {int ans = 0, size = height.length;for(int i = 0; i < size; i++) {int maxLeft = 0, maxRigth = 0;for(int j = i; j >= 0; j--) {maxLeft = Math.max(maxLeft, height[j]);}for(int j = i; j < size; j++) {maxRigth = Math.max(maxRigth, height[j]);}ans += Math.min(maxLeft, maxRigth) - height[i];}return ans;}}
双指针
class Solution {public int trap(int[] height) {int left = 0, right = height.length - 1;int leftMax = 0, rightMax = 0, ans = 0;while(left < right) {leftMax = Math.max(leftMax, height[left]);rightMax = Math.max(rightMax, height[right]);if(height[left] < height[right]) {ans += leftMax - height[left];left++;} else {ans += rightMax - height[right];right--;}}return ans;}}
53.最大子序和
前缀和
class Solution {public int maxSubArray(int[] nums) {int n = nums.length;// 前缀和int[] prefixSum = new int[n];int sum = 0;for(int i = 0; i < n; i++) {prefixSum[i] = sum + nums[i];sum = prefixSum[i];}int maxSum = Integer.MIN_VALUE;for(int i = 0; i < n; i++) {for(int j = 0; j <= i; j++) {maxSum = Math.max(maxSum, prefixSum[i] - prefixSum[j] + nums[j]);}}return maxSum;}}
动态规划
class Solution {public int maxSubArray(int[] nums) {// 定义 dp[i] 为 第i个数结尾的连续子数组的最大和,那么dp[i] 的状态只能由 dp[i - 1] 或者 第 i 个数自身(nums[i])转移而来// 状态转移方程: dp[i] = max(dp[i - 1] + nums[i], nums[i]);int n = nums.length;int[] dp = new int[n];dp[0] = nums[0];int max = Integer.MIN_VALUE;for(int i = 1; i < n; i++) {dp[i] = Math.max(dp[i - 1] + nums[i], nums[i]);max = Math.max(max, dp[i]);}return Math.max(dp[0], max);}}
位运算
191.位1的个数(例题1)
public class Solution {// you need to treat n as an unsigned valuepublic int hammingWeight(int n) {int count = 0, mark = 1;for(int i = 0; i < 32; i++) {if((n & mark) != 0) {count++;}mark <<= 1;}return count;}}
461.汉明距离(例题2)
class Solution {public int hammingDistance(int x, int y) {// 先异或,求出来的二进制中 1 的个数代表汉明距离int p = x ^ y;int dist = 0, mask = 1;for(int i = 0; i < 32; i++) {if((p & mask) != 0) {dist++;}mask <<= 1;}return dist;}}
面试题05.06.整数转换
class Solution {public int convertInteger(int A, int B) {int count = 0, p = A ^ B, mark = 1;for(int i = 0; i < 32; i++) {if((p & mark) != 0) {count++;}mark <<= 1;}return count;}}
面试题05.07.配对交换
class Solution {public int exchangeBits(int num) {int ret = 0;for(int i = 0; i <= 30; i+=2) {int a = num & (1 << i);int b = num & (1 << (i+1));if(a != 0) {ret += (1 << (i + 1));}if(b != 0) {ret += 1 << i;}}return ret;}}
面试题05.01.插入
class Solution {public int insertBits(int N, int M, int i, int j) {// 将i ~ j 范围的数取0for(int k = i; k <= j; k++) {N ^= (N & (1 << k));}// M 左移 i 位M <<= i;// 进行或运算return N | M;}}
面试题17.04.消失的数字
class Solution {public int missingNumber(int[] nums) {int n = nums.length;int ret = 0, i = 0;while(i < n) {ret ^= i ^ nums[i];i++;}return ret ^ n;}}
剑指Offer 56 - I.数组中数字出现的次数
题解思路:
已知:两数相等异或结果为0,一个数与0异或结果就等于其本身。 所以如果数组中只有一个出现一次的数,那么就只需要对所有的数进行异或就可以得到这个只出现一次的数,而本题中出现一次的数有两个。 所以所有数异或的结果就是那两个只出现一次的数异或的结果。 所以根据这个特性,我们就可以采用分组的方法解决此问题。且分组要满足两个条件: 1、两个相同的数必须出现在同一组。
2、那两个只出现一次的数必须分配在不同的组。
这样我们分别对这两组数进行异或,就可以得到两个出现一次的数。
那么,究竟应该怎么分组呢?
例如【4,1,4,6】:全部异或的结果就是1和6异或的结果。就是0001和0110异或的结果0111。其实我们不难发现。将该两个相同的数分配在一组是很容易实现的。我们只需要固定一个二进制位,若这两个数在这个二进制位上的数是相同的。我们就把他分在同一组。但是难点还是在如何实现将两个子出现一次的数分配在不同的组里面。
继续往下分析,1和6异或结果就是0111,0111这个二进制数中是1的二进制位暗含了什么个意思呢?
分析不难知道,二进制位是1,就表示1和6在这个二进制位上的数是不同的。所以,这就是我们划分两个数到不同组的依据。
因为0111有三个二进制位都是1,分别是第一位、第二位、第三位。这就表示了1和6的二进制数在第一、二、三位上的数是不同的。我们假设就以第一个二进制位为划分标准。当数组中的数的第一个二进制位是1的就分为第一组。数组中的数第一个二进制位是0的就划分为第二组。这样就成功的将1和6分到了不同的组别中,而相同的数例如4,因为4和4的第一个二进制位是必然相等的,这样也就实现了将两个相同的数划分到同一组。最后只需要分别将这两个组进行异或,就可以得到我们要求的答案。
摘自:https://leetcode-cn.com/problems/shu-zu-zhong-shu-zi-chu-xian-de-ci-shu-lcof/solution/shu-zu-zhong-shu-zi-chu-xian-de-ci-shu-by-leetcode/ 三生烟火 网友的回答
class Solution {public int[] singleNumbers(int[] nums) {int xOrResult = 0;int n = nums.length;for(int i = 0; i < n; i++) {xOrResult ^= nums[i];}int tag = 1;// 找出第一位为1的位数,作为分隔符while((xOrResult & tag) == 0) {tag <<= 1;}int a = 0, b = 0;for(int i = 0; i < n; i++) {if((tag & nums[i]) == 0) {a ^= nums[i];} else {b ^= nums[i];}}return new int[]{a, b};}}
剑指Offer 56 - II.数组中数字出现的次数II
class Solution {public int singleNumber(int[] nums) {int[] bits = new int[32];for(int i = 0; i < bits.length; i++) {int tag = 1 << i;for(int num : nums) {if((num & tag) != 0) {bits[i] = (bits[i] + 1) % 3;}}}int result = 0;int mark = 1;for(int i = 0; i < bits.length; i++) {result += bits[i] * mark;mark <<= 1;}return result;}}
面试题16.01.交换数字
解题思路:有两个数,分别为 a、b,经过 a = a^b , b = a^b , a = a^b 后,a 与 b 的值互换。
class Solution {public int[] swapNumbers(int[] numbers) {if(numbers[0] == numbers[1]) {return numbers;}numbers[0] ^= numbers[1];numbers[1] ^= numbers[0];numbers[0] ^= numbers[1];return numbers;}}
231. 2的幂
class Solution {public boolean isPowerOfTwo(int n) {return n > 0 && (n & (n - 1)) == 0;}}
