96. Unique Binary Search Trees-唯一二叉排序树的个数
-
题目描述
- 1) 当节点个数为0或1时,二叉树只有1种,表示为f(0)=1,f(1)=f(0)*f(0);
2) 当节点个数为2时,总的种类数=左子树为空f(0)右子树不为空f(1)+左子树不为空f(1)右子树为空f(0),即f(2) = f(0)*f(1)+f(1)*f(0)=2种;
3) 当节点个数为3时,有左子树为空f(0)右子树不为空f(2)+左子树不为空f(2)右子树为空f(0)+左右子树均不为空f(1)*f(1),即f(0)*f(2)+f(2)*f(0)+f(1)*f(1)=1*2+2*1+1*1=5种;
4) 当节点个数为n时,结果为f(0)*f(n-1)+f(1)*f(n-2)+……+f(n-2)*f(1)+f(n-1)*f(0);
代码实现
思路分析
public class Solution {
public int numTrees(int n) {
int[] a = new int[n + 1];
a[0] = 1;
a[1] = 1;
for(int i = 2; i <= n; i ++) {
for(int j = 0; j < i; j ++) {
a[i] += a[j] * a[i - 1 - j];
}
}
return a[n];
}
}
算法-229. Majority Element II
-
题设条件
- Given an integer array of size n, find all elements that appear more than ⌊ n/3 ⌋ times. The algorithm should run in linear time and in O(1) space.
- 由题设条件可知,一个数组里面最多有两个出现次数大于n/3的元素。所以,可以借鉴169. Majority Element的模式,用两个计数器对众数进行计数。时间复杂度O(n),空间复杂度O(n) 代码实现
思路分析
public List<Integer> majorityElement(int[] nums) {
int len = nums.length;
int count1 = 0, count2 = 0;// 对众数元素进行计数
int ele1 = 0, ele2 = 0;// 存储两个众数元素
// 依次遍历数组,初步找出可能的两个众数
for (int num : nums) {
if (num == ele1) {
ele1 = num;
count1++;
} else if(num == ele2) {
ele2 = num;
count2++;
} else if (count1 == 0) {
ele1 = num;
count1++;
} else if (count2 == 0) {
ele2 = num;
count2++;
} else {
count1--;
count2--;
}
}
// 已存的元素ele1/ele2不一定都是众数,需要进行确认
count1 = 0, count2 = 0;
for (int num : nums) {
if (num== ele1)
count1++;
else if (num == ele2) {
count2++;
} else
continue;
}
// 返回结果
List<Integer> list = new LinkedList<Integer>();
if (count1 > n/3)
list.add(ele1);
if (count2 > n/3)
list.add(ele2);
return list;
}
算法-228. Summary Ranges
-
题设条件
- Given a sorted integer array without duplicates, return the summary of its ranges.
For example, given [0,1,2,4,5,7], return [“0->2”,”4->5”,”7”].
- 用两个索left, right引分别记录子序列的开头和当前位置,依次将right右移,判断nums[right]是否为前一个元素加一。需要特别注意首位元素均独自成子序列的情况。 代码实现
思路分析
public List<String> summaryRanges(int[] nums) {
int len = nums.length;
List list = new LinkedList<String>();// 存储返回的结果
int left = 0, right = 0;// 子序列索引,默认从0开始
// 依次遍历数组
for (right = 1; right < len; right++) {
if (nums[right] == nums[right-1] + 1) {// 如果当前元素比前一个值大一,即元素连续
continue;
} else {// 元素不连续
// 判断起始点是否同一位置
if (left == right-1) {
list.add(nums[left]+"");
} else {
list.add(nums[left]+"->"+nums[right-1]);
}
// 更新左指针
left = right;
}
}
// 对最后一个子序列进行处理
if (left == right - 1) {// 最后一个子序列只有一个元素
list.add(left+"");
} else {// 最后子序列不止一个元素
list.add(left+"->"+right);
}
// 返回结果
return list;
}
算法-268. Missing Number
-
题设条件
- Given an array containing n distinct numbers taken from 0, 1, 2, …, n, find the one that is missing from the array.
For example, Given nums = [0, 1, 3] return 2.Note:Your algorithm should run in linear runtime complexity. Could you implement it using only constant extra space complexity?
思路分析(时间复杂度O(n),空间复杂度O(1))
- 假设数组中不缺元素时,数组元素从0到n;当数组中缺一个元素时,数组的长度为n,即成为当前题设的数组。所以,要求得所缺少的元素,只需将原数组求和,减去现有数组元素值即可。 代码实现
public int missingNumber(int[] nums) {
int len = nums.length;// 获取现有数组长度
long sum = (0 + n) * (n + 1) >> 1;// 计算原始数组和
// 依次减去当前数组元素
for (int num : nums) {
sum -= num;
}
// 类型转换,然后返回
return (int)sum;
}
- 根据异或操作性质:任意数字异或自身得到0,任意数字异或0保持不变。将数组中的每个元素与对应的索引做异或,第二个元素与对应索引做异或……将异或结果相异或,得到数组元素与所有索引的异或值。将最后的结果再与数字n相异或,即可得到锁缺少的数字。 代码实现
思路分析(时间复杂度O(n),空间复杂度O(1))
public int missingNumber(int[] nums) {
int len = nums.length;
int res = 0;// 保存累计异或值
// 依次对数组元素与索引进行异或
for (int i = 0; i < len; i++) {
res = nums[i] ^ i ^ res;
}
// 将当前累计异或值与len异或,即可得到所缺少的数字
return res ^ len;
}
- 题设没有说当前数组有序,对于升序数组,可以采用二分查找的方法进行缺少元素的查找。此种情况,出去排序过程,时间复杂度O(log(n)),空间复杂度O(1))
思路分析
代码实现
public int missingNumber(int[] nums) {
int len = nums.length;
int start = 0, end = len - 1;
while (start < end) {
int mid = (start + end) >> 1;
// 若数组连续,则nums[i] == i
if (nums[mid] == mid) {// mid左边的所有元素均连续
start = mid + 1;
} else {// mid 左边的元素不连续
end = mid;
}
}
// 此时start == end,所指元素减一即为缺省元素
return nums[start] - 1;
}
算法-219. Contains Duplicate II
-
题设条件
- Given an array of integers and an integer k, find out whether there are two distinct indices i and j in the array such that nums[i] = nums[j] and the absolute difference between i and j is at most k.
- 利用一个窗,宽度为k,将窗口依次向右移动,删除窗口最左边的元素,添加窗口最右边的下一个元素。首先,需要判断给定值k与数组长度len的关系。窗口可以用hashset集合来表示。| i-j | <= k,窗口中最多包含k+1个元素。
思路分析
代码实现
public boolean containsNearbyDuplicate(int[] nums, int k) {
int len = nums.length;
HashSet<Integer> hashset = new HashSet<Integer>();
// 首先,对k进行判断
if (k > len)
k = len;
// 对数组中的元素依次进行添加
for (int i = 0; i < k; i++) {// 往集合中放入k个元素
hashset.add(nums[i]);
}
// 判断前k个元素有无重复
if (hashset.size() < k) {// 有重复
return true;
} else {// 前k个元素无重复
for (int i = k; i < len; i++) {
if (hashset.add(nums[i])) {// 成功添加进去一个,移除最早的元素
hashset.remove(nums[i-k]);
} else {// 添加元素失败
return true;
}
}
return false;
}
}
算法-217. Contains Duplicate
-
题设条件
- Given an array of integers, find if the array contains any duplicates. Your function should return true if any value appears at least twice in the array, and it should return false if every element is distinct.
- 将数组元素全部放入set集合,然后判断set集合元素个数与数组长度的关系,时间复杂度O(n),空间复杂度O(n)
思路分析
代码实现
public boolean containsDuplicate(int[] nums) {
int len = nums.length;
HashSet<Integer> hashset = new HashSet<Integer>();
// 数组元素添加进hashset
for (int num : nums)
hashset.add(num);
if (hashset.size() == len)
return false;
else
return true;
}
算法-169. Majority Element
-
题设条件
- Given an array of size n, find the majority element. The majority element is the element that appears more than ⌊ n/2 ⌋ times.
You may assume that the array is non-empty and the majority element always exist in the array.
- 设nums[0]为众数majority,出现次数记为count=1。依次遍历后续元素nums[i],若nums[i] == majority,则count++;若nums[i] != majority,则count–;若count<0,则majority=nums[i], count=1。总体思想是:众数出现的总次数可以抵消其他数字出现的次数和。
思路分析
代码实现
public int majorityElement(int[] nums) {
int len = nums.length;
int majority = nums[0];
int count = 1;
// 依次遍历后续元素
for (int i = 1; i < len; i++) {
if (majority == nums[i]) {// 出现当前众数,计数加一
count++;
} else {// 未出现当前众数,计数减一
count--;
}
// count < 0时,更新当前众数
if (count < 0) {
majority = nums[i];
count = 1;
}
}
return majority;
}
算法-209. Minimum Size Subarray Sum
-
题设描述
- Given an array of n positive integers and a positive integer s, find the minimal length of a subarray of which the sum ≥ s. If there isn’t one, return 0 instead.
For example, given the array [2,3,1,2,4,3] and s = 7, the subarray [4,3] has the minimal length under the problem constraint
思路分析
- 利用双指针法,左边的指针记录当前子数组的起点,右边的指针记录当前子数组的终点。右边的指针不断向右移,当sum大于s时,左边的指针也向右移动。
代码实现
public int minSubArrayLen(int s, int[] nums) {
int len = nums.length;
int width = Integer.MAX_VALUE;// 记录子数组宽度
int sum = 0;// 记录子数组和
int left = 0;// 左边指针
// 依次将右指针前移
for (int right = 0; right < len; right++) {
sum += nums[right];
while (sum >= s) {// 当前子数组和满足条件,记录下现在的宽度,左指针右移
width = Math.min(width, right-left+1);
sum -= nums[left];
left++;
}
}
// 若不存在这样的子数组,则width=Integer.MAX_VALUE,应该返回0
return width==Integer.MAX_VALUE ? 0 : width;
}
算法-204.Count Primes
-
题设描述
- Count the number of prime numbers less than a non-negative number, n.
- 采用素数筛选法
思路分析(最优解,时间复杂度O(n),空间复杂度O(n))
代码实现
public int countPrimes(int n) {
boolean[] flag = new boolean[n]{};// 标识数组,默认元素都是素数,然后一个个排除。
// 当元素为false时,表明索引数字为素数;元素为true时,索引数字非素数。利用flag数组的默认值,省略数组初始化。
int count = 0;// 统计素数个数,边过滤边统计
for (int i = 2; i < n; i++) {
if (!flag[i]) {// 当前元素为素数,则过滤掉倍数
count++;
for (int k = i * 2; k < n; k += i) {
flag[k] = true;
}
} else {// 非素数
continue;
}
}
return count;
}
算法-189. Rotate Array
-
题设条件
- Rotate an array of n elements to the right by k steps.
For example, with n = 7 and k = 3, the array [1,2,3,4,5,6,7] is rotated to [5,6,7,1,2,3,4] - 通过镜像的方法达到数据的循环右移。首先,对整体数组以中间元素为轴进行镜像,得到原始数组的逆序;然后,左边[start, k]的子数组以子数组的中间元素为轴进行镜像;同样的方法对[k+1, end]子数组进行镜像;最后得到演示数组循环右移k次的数组。
思路分析(最优解,时间复杂度O(n), 空间复杂度O(1))
代码实现
public void rotate(int[] nums, int k) {
int len = nums.length;
int tmp = 0;// 作为交换的临时变量
k = k % len;// 避免k大于len时的无效移动
// 首先,对整体数组以中间元素为轴进行镜像
imag(nums, 0, len - 1);
// 然后,对[0, k-1]子数组进行镜像
imag(nums, 0, k-1);// 注意是k-1,共k个元素
// 最后,对[k, len - 1]子数组进行镜像,得到原始数组循环右移k次的结果
imag(nums, k, len-1);
return;
}
// 实现数组镜像的方法
public void imag(int[] nums, int start, int end) {
int tmp = 0;
while(start < end) {
tmp = nums[start];
nums[start] = nums[end];
nums[end] = tmp;
start++;
end--;
}
return;
}
- 对数组元素进行复制。由于数组是传递引用,为了达到在原始数组上修改的目的,需要先将原始数组进行复制。
思路分析(一般解,时间复杂度O(n),空间复杂度O(n))
代码实现
public void rotate(int[] nums, int k) {
int len = nums.length;
k = k % len;
int[] tmp = new int[len];
// 对原始数组进行复制
for (int i = 0; i < len; i++) {
tmp[i] = nums[i];
}
// 将tmp数组元素复制到原始数组,并且是索引有偏移
for (int i = 0; i < len; i++) {
int index = (i + k) % len;
nums[index] = tmp[i];
}
return;
}
算法-167. Two Sum II - Input array is sorted
-
题设条件
- Given an array of integers that is already sorted in ascending order, find two numbers such that they add up to a specific target number.
The function twoSum should return indices of the two numbers such that they add up to the target, where index1 must be less than index2.Please note that your returned answers (both index1 and index2) are not zero-based.
You may assume that each input would have exactly one solution.Input: numbers={2, 7, 11, 15}, target=9
Output: index1=1, index2=2
思路分析(最优解,双索引法,时间复杂度O(n),空间复杂度O(1))
- 两个索引分别指向左右两边,移动索引向两边靠拢。若nums[start]+nums[end]>target,则end–;否则start++
public int[] twoSum(int[] nums, target) {
int start = 0, end = nums.length - 1;
while (start < end) {
sum = nums[start] + nums[end];
if (sum < target) {
start++;
} else if(sum > target) {
end--;
} else {// 找到了
break;
}
}
return new int[]{start+1, end+1};// 索引从1开始计
}
-
思路分析(次优解,二分查找,时间复杂度O(n*log(n)),空间复杂度O(1))
- 从左至右遍历元素,对于每一个元素值nums[i],利用二分查找在[i, end]区间查找target-nums[i]值。 代码实现
public int[] twoSum(int[] nums, int target) {
int len = nums.length;
for (int index1 = 0; index1 < len - 1; index1++) {
int sub = target - nums[index1];// 计算待查找的值
int index2 = java.util.Arrays.binarySearch(nums, index1+1, len, sub);// 二分查找,查找成功返回索引;查找失败返回(-(插入点-1)),即一个负数,不一定是-1
if (index2 >= 0) {// 查找成功
return new int[]{index1, index2};
}
}
return null;
}
-
思路分析(一般解,二重循环)
- 代码省略
算法-162. Find Peak Element
-
题设条件
- A peak element is an element that is greater than its neighbors.
Given an input array where num[i] ≠ num[i+1], find a peak element and return its index.
The array may contain multiple peaks, in that case return the index to any one of the peaks is fine.
You may imagine that num[-1] = num[n] = -∞.
For example, in array [1, 2, 3, 1], 3 is a peak element and your function should return the index number 2.
思路分析(次优解,时间复杂度O(n), 空间复杂度O(1))
- 题设条件指出nums[-1] = nums[n] = -∞,而nums[i] != -∞(0 <= i < n),表明序列在定义域内会首先出现上升,然后一定有下降。所以,只需要找出序列的第一个下降点,前一个点即为其中一个峰值;如果找不出下降点,由nums[n] = -∞可知,nums[len-1]一定为峰值
代码实现
public int findPeakElement(int[] nums) {
int len = nums.length;
for (int i = 1; i < len; i++) {
if (nums[i] < nums[i-1])
return i-1;
else
continue;
}
//如果没有找到,则nums[len - 1]一定为峰值
return len - 1;
}
-
思路分析(最优解,二分查找法,时间复杂度O(log(n)), 空间复杂度O(1))
- 通过不断缩小峰值范围来查找峰值。每一个查找都将nums[mid]与nums[mid+1]相比较,若nums[mid]nums[mid+1],则峰值在[start, mid]区间。 代码实现
public int findPeakElement(int[] nums) {
int start = 0, end = nums.length-1;
while(start < end) {
int mid = (start + end) >>1;
if(nums[mid] <nums[mid+1]) {// 有一个峰值在mid+1右边
start = mid + 1;
} else {// 有一个峰值在mid左边
end = mid;
}
}
return start;
}
二分的递归实现
public int findPeakElement(int[] nums) {
return findPeakElement(nums, 0, nums.length - 1);
}
public int findPeakElement(int[] nums, int start, int end) {
if (start < end) {// 递归进行的条件
int mid = (start + end) >> 1;
if (nums[mid] < nums[mid+1]) {// 峰值在mid+1右边
return findPeakElement(nums, mid+1, end);
} else {// 峰值在mid左边
return findPeakElement(nums, start, mid);
}
} else {// 递归结束条件
return start;
}
}
算法-154. Find Minimum in Rotated Sorted Array II
-
题设条件
- Suppose a sorted array is rotated at some pivot unknown to you beforehand.(i.e., 0 1 2 4 5 6 7 might become 4 5 6 7 0 1 2).Find the minimum element.
The array may contain duplicates.
思路描述
- 同153题,从左至右找数组元素第一个下降点的方法
代码实现
public int findMin(int[] nums) {
int len = nums.length;
int min = nums[0];
for (int i = 0; i < len - 1; i++) {
if (nums[i] < nums[i+1]) {
continue;
} else {
min = nums[i+1];
break;
}
}
return min;
}
算法-153. Find Minimum in Rotated Sorted Array
-
题设条件
- Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand.(i.e., 0 1 2 4 5 6 7 might become 4 5 6 7 0 1 2).Find the minimum element.
You may assume no duplicate exists in the array.
思路分析(次优解,T(n) = O(n), S(n) = O(1))
- 对于升序数组nums的循环移动,设移动步长为steps,若steps % nums.length,则最小值为nums[0];若steps % nums.length != 0,则最小值为从左到右第一个下降点。
代码实现
public int findMin(int[] nums) {
if (nums == null)
throw new NullPointerException("nums == null");
else {
int min = nums[0];
int len = nums.length;
for (int i = 0; i < len - 1; i++) {
if (nums[i] < nums[i + 1])
continue;
else {
min = nums[i + 1];
break;
}
}
return min;
}
}
-
思路分析(最优解——二分查找,时间复杂度O(log(n)), 空间复杂度O(1))
- 取数组的中间位置的值:如果它比数组末尾的值大,说明最小元素就位于[mid + 1, right]之间。否则,最小元素一定在[left, mid]中。
代码实现
public int findMin(int[] nums) {
int len = nums.length;
int start = 0, end = len - 1;
while (start < end) {
int mid = (start + end) >> 1;
if(nums[mid] < nums[end]) {// 后半部分有序,下降点在前半部分
end = mid;
} else {// 前半部分有序,下降点在后半部分
start = mid + 1;
}
}
return nums[start];
}
基于递归的二分算法
public int findMin(int[] nums) {
return find(nums, 0, nums.length - 1);
}
public int find(int[] nums, int start, int end) {
if (start < end) {
int mid = (start + end) >> 1;
if (nums[mid] < nums[end]) {// 后半部分有序
return find(nums, start, mid);
} else {// 前半部分有序
return find(nums, mid + 1, end);
}
} else {
return nums[start];
}
}
算法-142.Linked List Cycle ||
-
题设条件
- Given a linked list, return the node where the cycle begins. If there is no cycle, return null.
Note: Do not modify the linked list.
- 判断链表环路问题,用快慢指针法。
- 所以,若两个指针分别从start点和meet点同步出发,步长均为1,则下一个相遇点一定在环的起点。
思路分析
代码实现
public ListNode detectCycle(ListNode head) {
ListNode fast = head, slow = head;// 快慢指针,起点相同
ListNode result = null;// 返回结果
// 先判断链表是否存在环
while (fast != null && fast.next != null) {
fast = fast.next.next;
slow = slow.next;
if (fast == slow)
break;
else
continue;
}
if (fast == null || fast.next == null)// 不存在环
result = null;
else{// 存在环
// 快指针回到start点,慢指针保持在meet点,两指针同步移动,步长均为1,第一次相遇点即为环路起点
fast = head;
while (fast != slow) {
fast = fast.next;
slow = slow.next;
}
result =slow;
}
return result;
}
算法-2. Add Two Numbers
-
题设条件
- You are given two non-empty linked lists representing two non-negative integers. The digits are stored in reverse order and each of their nodes contain a single digit. Add the two numbers and return it as a linked list.
You may assume the two numbers do not contain any leading zero, except the number 0 itself.
Input: (2 -> 4 -> 3) + (5 -> 6 -> 4)
Output: 7 -> 0 -> 8 - 同步遍历两个链表,将对应节点值相加存入新建链表,返回新建链表的头部
思路分析
代码实现
初始版本
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
ListNode head = new ListNode(0), curr = head;// 新建链表的头指针、当前访问指针
int sum = 0, carry = 0;// 分别存储两个数字的加和、进位
// 同时遍历两个列表
while (l1 != null && l2 != null) {
sum = l1.val + l2.val + carry;
curr.next = new ListNode(sum % 10);
carry = sum / 10;
curr = curr.next;
l1 = l1.next;
l2 = l2.next;
}
// l1链表比较长
while (l1 != null) {
sum = l1.val + carry;
curr.next = new ListNode(sum % 10);
carry = sum / 10;
curr = curr.next;
l1 = l1.next;
}
// l2链表比较长
while (l2 != null) {
sum = l2.val + carry;
curr.next = new ListNode(sum % 10);
carry = sum / 10;
curr = curr.next;
l2 = l2.next;
}
// 最后若有进位,需要再新建节点
if (carry != 0)
curr.next = new ListNode(carry);
// 返回不包含头结点的链表
return head.next;
}
改进版本:只需要一个while循环,在循环里面判断链表是否遍历结束
// 改进版
public ListNode addTwoNumbers2(ListNode l1, ListNode l2) {
ListNode head = new ListNode(0);// 新建链表的头结点
ListNode curr = head;// 新建链表的当前指针位置
int sum = 0;// 存储加和信息
// 两个链表没有全部遍历结束
while (l1 != null || l2 != null) {
if (l1 != null) {// l1链表没有结束
sum += l1.val;
l1 = l1.next;
}
if (l2 != null) {// l2链表没有结束
sum += l2.val;
l2 = l2.next;
}
curr.next = new ListNode(sum % 10);// 存储相加的结果,不包含进位
curr = curr.next;// 当前指针后移
sum /= 10;// sum不清零,自动包含进位信息
}
// 判断最后有无进位
if (sum != 0) {
curr.next = new ListNode(sum);
}
// 返回不带头结点的链表
return head.next;
}
算法-7-Rerverse Integer
-
题目描述
- Reverse digits of an integer.
Example1: x = 123, return 321
Example2: x = -123, return -321Note:The input is assumed to be a 32-bit signed integer. Your function should return 0 when the reversed integer overflows.
代码实现
public class Solution {
public int reverse(int x) {
long sum = 0;// 反转后的新数字绝对值,采用long类型防止整型反转后溢出
int bounder = (int)(Math.pow(2, 31) - 1);// 注意区分异或^运算与指数运算
int flag = 1;// 符号标识
if (x < 0) {
flag = -1;
x *= flag;
}
while (x > 0) {
sum *= 10;
sum += x%10;
x /= 10;
}
if (sum > bounder)// 判断溢出
return 0;
else
return (int)sum*flag;
}
}
算法-141. Linked List Cycle
-
题设条件
- Given a linked list, determine if it has a cycle in it.
Follow up:
Can you solve it without using extra space? - 对于环形链表,采用快慢指针法:两个指针同步移动,快指针每次走2步,慢指针每次走1步,所以每移动一次快指针比慢指针多走一步。因为每次多走一步,所以当链表存在环路时,快指针一定能遇到慢指针而不会跳过。
思路分析
代码实现
public boolean hasCycle(ListNode head) {
ListNode fast = head, slow = head;// 快慢指针从同一位置出发
// 若快指针没有遍历到链表结尾
while (fast != null && fast.next != null) {
fast = fast.next.next;// 快指针走两步
slow = slow.next;// 慢指针走一步
// 判断快慢指针是否相遇,若相遇代表链表存在环,直接返回
if (fast == slow)
return true;
}
// 快指针走到头,依然没相遇
return false;
}
算法-从数组中找出子序列的最大和
-
题设条件
- 给定一个整型数组,数组元素e(e>0或e<0或e=0),求数组中子序列的最大和。
- 此题属于动态规划问题,当前问题的结果基于前一个子问题。用max变量记录子序列的最大和,用sum变量记录当前子序列的和。每迭代一个元素,先将元素加入sum;若此时sum大于max,则更新max;若sum<0,则将sum置0;否则跳过,继续遍历。
思路分析
代码实现
public class MySolution1 {
public int getMaxSum(int[] arr) {
int max = 0;// 记录子序列最大值
int sum = 0;// 记录当前子序列的值,即动态规划的前一个问题结果
// 依次遍历数组元素
for (int item : arr) {
sum += item;
if (sum > max)
max = sum;
else if (sum < 0)
sum = 0;
else
continue;
}
return max;
}
}
算法-大数据求交集
-
题设条件
- 求两个整数数组的交集,如下:int[] array1={2,6,3,9,4},int[] array2={4,7,9,1},array1,array2数组长度分别为N,M,交集
为:{4,9}。 - 将array1中的每个元素与array2中的每个元素逐个进行比较,二重循环。时间复杂度为O(N*M),空间复杂度为O(1)
解答一(暴力法)
for (int arr1 : array1) {
for (int arr1 : array2) {
//
}
}
- 首先对array1进行排序,然后将array2中的元素逐个取出,在array1中用二分法逐个查找元素。array1的排序时间复杂度为O(N*log(N)),每搜索一个元素的时间复杂度为O(log(N)),所以总的时间复杂度为O(N*log(N)) + M*O(log(N))。若对array2进行排序,查找array1中的元素,则时间复杂度为O(M*log(M))+N*O(log(M))。
对两个复杂度,如图 分析结果可知,对较短数组进行排序的复杂度小一些。
- 分别对两个数组进行升序排序,排序完毕后同时遍历两个数组。如果array1[index1]>array2[index2],则index2++;如果array1[index1] < array2[index2],则index1++;如果array1[index1]==array2[index2],则找到交集的一个元素,index1++、index2++。排序的时间复杂度为O(N*log(N))+O(M*log(M)),比较的时间复杂度为O(min(N,M)),总的时间复杂度为O(N*log(N)) + O(M*log(M)) + O(min(N, M))。
- 分别将两个数组中的数据存入哈希集合中,最后遍历哈希集合即可得到交集。这是以空间换时间,时间复杂度为O(N+M),空间复杂度为O(N+M)。
- 当数据集特别大时,可以用MapReduce过程处理,用N个map任务和一个reduce任务。首先对原始数组中的数据进行分组,通过hash(item)%N将数组中的数据分到各个Map任务中;在每个Map任务中求两个子数组的交集;最后将各个map的结果输入到reduce端即可得出总体数据的交集。
解答二(单排序后进行比较)
解答三(双排序后进行比较)
解答四(哈希表)
解答五(MapReduce思想)
算法-约瑟夫环问题
-
问题描述
- number个人围成一圈,从第start个人开始数起,每数到第distance个人则拉出来;然后,再从下一个开始计数……直到剩下最后一个人。求每个人的出环顺序。 思路分析
- 用一个List链表存储每个元素,每次出队的元素索引index为(start+distance-1)%list.size(),出队后更新start为index。list容量为1时退出循环。
代码实现
public List<Integer> Josephus(int number, int start, int distance) {
List<Integer> cycle = new ArrayList<Integer>();// 约瑟夫环
List<Integer> res = new ArrayList<Integer>();// 存储出环结果
// 对环进行初始化
for (int i = 1; i <= number; i++) {
cycle.add(i);
}
// 依次出队
while (cycle.size() > 1) {
int index = (start + distance - 1) % cycle.size();// 出环索引
res.add(cycle.remove(index));
start = index;
}
System.out.println(cycle.get(0));
return res;
}