public static void main(String[] args) throws Exception {
int[] nums = {1, 3, 4, 2, 2};
int len = nums.length;
if (len == 0) {
return;
}
int dp[] = new int[len];
dp[0] = 1;
int maxAns = 1;
for (int i = 1; i < len; i++) {
dp[i] = 1;
for (int j = 0; j < i; j++) {
if (nums[i] > nums[j]) {
dp[i] = Math.max(dp[i], dp[j] + 1);
}
}
maxAns = Math.max(dp[i], maxAns);
}
System.out.println(maxAns);
}
示例 1:
输入:nums = [1,3,4,2,2]
输出:2
快慢指针法
class Solution {
public int findDuplicate(int[] nums) {
int slow = 0, fast = 0;
do {
slow = nums[slow];
fast = nums[nums[fast]];
} while (slow != fast);
slow = 0;
while (slow != fast) {
slow = nums[slow];
fast = nums[fast];
}
return slow;
}
}
class Solution {
public int[] productExceptSelf(int[] nums) {
int length = nums.length;
int[] answer = new int[length];
// answer[i] 表示索引 i 左侧所有元素的乘积
// 因为索引为 '0' 的元素左侧没有元素, 所以 answer[0] = 1
answer[0] = 1;
for (int i = 1; i < length; i++) {
answer[i] = nums[i - 1] * answer[i - 1];
}
// R 为右侧所有元素的乘积
// 刚开始右边没有元素,所以 R = 1
int R = 1;
for (int i = length - 1; i >= 0; i--) {
// 对于索引 i,左边的乘积为 answer[i],右边的乘积为 R
answer[i] = answer[i] * R;
// R 需要包含右边所有的乘积,所以计算下一个结果时需要将当前值乘到 R 上
R *= nums[i];
}
return answer;
}
}
public static void main(String[] args) throws Exception {
int[] nums = {2,3,-2,4,-1,5};
int maxF = nums[0],minF = nums[0],ans = nums[0];
int length = nums.length;
for(int i=1;i<length;i++){
int mx = maxF, mn = minF;
maxF = Math.max(mx*nums[i],Math.max(mn*nums[i],nums[i]));
minF = Math.min(mn*nums[i], Math.min(mx*nums[i], nums[i]));
ans = Math.max(maxF,ans);
}
System.out.println(ans);
}
示例 1:
输入:nums = [2,0,2,1,1,0]
输出:[0,0,1,1,2,2]
public static void sortColors(int[] nums) {
int n = nums.length;
int l = 0, r = n - 1;
for (int i = 0; i <= r; i++) {
// 右指针r存2
while (i <= r && nums[i] == 2) {
int temp = nums[i];
nums[i] = nums[r];
nums[r] = temp;
r--;
}
// 左指针l存0
if (nums[i] == 0) {
int temp = nums[i];
nums[i] = nums[l];
nums[l] = temp;
l++;
}
}
}
哈希法
public static void main(String[] args) throws Exception {
int[] temperatures = {4, 5, 6, 7, 0, 1, 2};
Set<Integer> set = new HashSet<>();
for (int a : temperatures) {
set.add(a);
}
int longLen = 0;
for (int b : temperatures) {
if (!set.contains(b - 1)) {
int currNum = b;
int currLen = 1;
while (set.contains(currNum + 1)) {
currNum += 1;
currLen += 1;
}
longLen = Math.max(longLen, currLen);
}
}
System.out.println(longLen);/**/
}
二分法
在这里插入代码片
public static void main(String[] args) throws Exception {
int[] temperatures = {4, 5, 6, 7, 0, 1, 2};
int target = 4;
int s = search(temperatures, target);
System.out.println(s);
}
public static int search(int[] nums, int target) {
int len = nums.length;
if (len == 0) {
return -1;
}
if (len == 1) {
return nums[0] == target ? 0 : 1;
}
int l = 0, r = len - 1;
if (l < r) {
int mid = (r + l) / 2;
if (nums[mid] == target) {
return mid;
}
if (nums[0] <= nums[mid]) {
if (target < nums[mid] && target >= nums[0]) {
r = mid - 1;
} else {
l = mid + 1;
}
} else {
if (target >= nums[mid] && target < nums[mid]) {
l = mid + 1;
} else {
r = mid - 1;
}
}
}
return -1;
}
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有满足条件且不重复的三元组。
注意:答案中不可以包含重复的三元组。
public static void main(String[] args) throws Exception {
int[] temperatures = {-1, -2, -3, 0, 5, 4, 1, 3, 2};
Arrays.sort(temperatures);
int len = temperatures.length;
List<Integer> lists = new ArrayList<>();
for (int first = 0; first < len; first++) {
if (temperatures[first] >= 0) {
break;
}
if (first > 0 && temperatures[first] == temperatures[first - 1]) {
continue;
}
int second = first + 1;
int last = len - 1;
while (second < last) {
if (second > first + 1 && temperatures[second] == temperatures[second - 1]) {
second++;
continue;
}
if (last < len - 1 && temperatures[last] == temperatures[last + 1]) {
last--;
continue;
}
int sum = temperatures[first] + temperatures[last] + temperatures[second];
if (sum == 0) {
lists.add(temperatures[first]);
lists.add(temperatures[second]);
lists.add(temperatures[last]);
second++;
last--;
} else if (sum > 0) {
last--;
} else {
second++;
}
}
}
lists.stream().forEach(item -> System.out.println(item));
}
def threeSum(nums):
# 定义一个空列表存储结果
alist = []
# 如果列表的长度小于2或者=None, 直接停止执行
if nums is None or len(nums) < 2:
return alist
# 排序后再找数据
nums.sort()
for i in range(len(nums)-2):
# 如果当前值>0,有序列表后面的值相加肯定都大于0,所有直接退出循环
if nums[i] > 0:
break
# 如果当前值和前面的值相等,会导致结果重复,所以应该跳过
if i > 0 and nums[i] == nums[i-1]:
continue
# l指向i后的第一个元素,称为左指针
l = i + 1
# r指向列表最后一个元素,称为右指针
r = len(nums) - 1
while l < r:
sum = nums[i] + nums[l] + nums[r]
if sum == 0:
alist.append((nums[i], nums[l], nums[r]))
# 如果左指针当前的值和下一个值相同,会导致重复,所以跳过
while l < r and nums[l] == nums[l + 1]:
l += 1
# 如果右指针当前的值和前一个值相同,会导致重复,所以跳过
while l > r and nums[r] == nums[r - 1]:
r -=1
l += 1
r -= 1
# 如果三个数的和大于0,说明右指针所指的值太大
elif sum > 0:
r -= 1
# 如果三个数的和小于0,说明左指针所指的值太小
else:
l += 1
return alist
if __name__ == '__main__':
nums = [-1, 2, -1,-2,0,2,-1]
print(threeSum(nums))
给你 n 个非负整数 a1,a2,…,an,每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0) 。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
说明:不能倾斜容器。
暴力法
public static void main(String[] args) throws Exception {
int[] temperatures = {1, 8, 6, 2, 5, 4, 8, 3, 7};
int len = temperatures.length;
int max = 0;
for(int i=0;i<len-1;i++){
for(int j=i+1;j<len;j++){
int temp = Math.min(temperatures[i],temperatures[j])*(j-i);
if(temp>max){
max = temp;
}
}
}
System.out.println(max);
}
双指针法
public static void main(String[] args) throws Exception {
int[] temperatures = {1, 8, 6, 2, 5, 4, 8, 3, 7};
int len = temperatures.length;
int ans = 0;
int left = 0;
int right = len - 1;
while (left < right) {
int temp = Math.min(temperatures[left], temperatures[right]) * (right - left);
if (temp > ans) {
ans = temp;
}
if (temperatures[left] <= temperatures[right]) {
left++;
} else {
right--;
}
}
System.out.println(ans);
}
请根据每日 气温 列表 temperatures ,请计算在每一天需要等几天才会有更高的温度。如果气温在这之后都不会升高,请在该位置用 0 来代替。
在这里插入代码片
public static void main(String[] args) throws Exception {
int n = 6;
if (n == 0) {
return;
}
int[] s = new int[n + 1];
s[1] = 1;
for (int i = 2; i < n + 1; i++) {
s[i] = s[i / 2] + i % 2 * s[i / 2 + 1];
}
System.out.println(Arrays.stream(s).max().getAsInt());
}
public static void main(String[] args) throws Exception {
int[] a = {1,7,9};
int l = a.length;
List<Integer> collect = Arrays.stream(a).boxed().collect(Collectors.toList());
List<Integer> ins = new ArrayList<>();
for(int i=1;i<=l;i++){
if(!collect.contains(i)){
ins.add(i);
}
}
ins.stream().forEach(item-> System.out.println(item));
}
public static void main(String[] args) throws Exception {
int[] a = {0, 1, 0, 3, 12};
int left = 0;
int right = 0;
while (right < a.length) {
if (a[right] != 0) {
a[left] = a[right];
left++;
}
right++;
}
while (left < a.length) {
a[left] = 0;
left++;
}
Arrays.stream(a).forEach(item -> System.out.println(item));
}
方法1:空间局部优化
统计0的个数;定义一个新列表,把非空的元素放前面,0放后面
def moveZeros(nums):
zero_num = 0
new_list = []
for i in range(len(nums)):
if nums[i] ==0:
zero_num += i
else:
new_list.append(nums[i])
for i in range(zero_num):
new_list.append(0)
for i in range(len(nums)):
nums[i] = new_list[i]
nums = [1, 2, 4, 0 ,4 ,8 ,0]
moveZeros(nums)
print(nums)
方法2::空间最优,操作局部优化(双指针)
非空元素往前移,剩下的位置填0
def moveZeroes(nums) :
lastNonZeroFoundAt = 0
for i in range(len(nums)):
if nums[i] != 0 :
nums[lastNonZeroFoundAt] = nums[i]
lastNonZeroFoundAt += 1
i += 1
for i in range(lastNonZeroFoundAt, len(nums)):
nums[i] = 0
nums = [1,3,0,4,0,2]
moveZeroes(nums)
print(nums)
给定一个大小为 n 的数组,找到其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。
int[] a = {2,2,1,1,1,2,2};
Arrays.sort(a);
System.out.println(a[a.length/2]);
一个整型数组 nums 里除两个数字之外,其他数字都出现了两次。请写程序找出这两个只出现一次的数字。
要求时间复杂度是O(n),空间复杂度是O(1)。
位运行
class Solution {
public int singleNumber(int[] nums) {
int single = 0;
for (int num : nums) {
single ^= num;
}
return single;
}
}
int[] nums = {4, 1, 2, 1, 2};
Set<Integer> set = new HashSet<>();
for(int i=0;i<nums.length;i++){
if(!set.add(nums[i])){
set.remove(nums[i]);
}
}
System.out.println(set.toArray()[0]);
def singleNumber(alist):
no_duplicate_list = []
for i in alist:
if i not in no_duplicate_list:
no_duplicate_list.append(i)
if i in no_duplicate_list:
no_duplicate_list.remove(i)
return no_duplicate_list.pop()
方法2:哈希操作
def singleNumber(nums):
hash_table = {}
for i in nums:
try:
hash_table.pop(i)
except:
hash_table[i] =1
return hash_table.popitem()[0]
方法3:数学
def singleNumber( nums):
return 2*sum(set(nums)) - sum(nums)
nums = [1,2,1,2,3]
print(singleNumber(nums))
public static void main(String[] args) throws Exception {
int[] nums = {7, 1, 5, 3, 6, 4};
int minprice = Integer.MAX_VALUE;
int maxprofit = 0;
for (int i = 0; i < nums.length; i++) {
if (nums[i] < minprice) {
minprice = nums[i];
} else if (maxprofit < nums[i] - minprice) {
maxprofit = nums[i] - minprice;
}
}
System.out.println(maxprofit);
}
def maxProfit(prices):
min_price = prices[0]
max_profit = 0
for i in range(1, len(prices)):
max_profit = max(max_profit, prices[i]-min_price)
min_price = min(prices[i], min_price)
return max_profit
m = [7,1,5,3,6,4]
r = maxProfit(m)
print(r)
def maxProfit(prices):
maxprofit = 0
for i in range(1, len(prices)):
if prices[i] > prices[i-1]:
maxprofit += prices[i] - prices[i-1]
return maxprofit
prices = [1,2,3,4,5]
mp = maxProfit(prices)
print(mp)
给定一个包含 0, 1, 2, …, n 中 n 个数的序列,找出 0 … n 中没有出现在序列中的那个数。
示例 1:
输入: [3,0,1]
输出: 2
def missingNumber(nums):
expected_sum = len(nums)*(len(nums)+1)//2
actual_sum = sum(nums)
return expected_sum -actual_sum
方法1:线性遍历
def contains_duplicate(nums):
for i in range(1, len(nums)):
for j in range(0, i):
if nums[j] == nums[i]:
return True
return False
nums = [1,2,3,4,3,2]
contains_duplicate(nums)
方法2:排序
def contains_duplicate(nums):
nums.sort()
i = 0
while i < len(nums):
if nums[i] == nums[i+1]:
return True
i += 1
return False
nums = [1,2,3,3,2]
s = contains_duplicate(nums)
print(s)
方法3:哈希
利用支持快速搜索和插入操作的动态数据结构。
import collections
def contains_duplicate(nums):
t = collections.Counter(nums)
for i in nums:
if t[i]>1:
return True
return False
nums = [1,2,3,3,2]
s = contains_duplicate(nums)
print(s)
方法4:利用set
def contains_duplicate(nums):
return True if len(set(nums)) != len(nums) else False
nums = [1,2,3,3,2]
s = contains_duplicate(nums)
print(s)
public static void main(String[] args) throws Exception {
int[] nums = {-2, 1, -3, 4, -1, 2, 1, -5, 4};
int pre = 0, maxAns = nums[0];
for(int x: nums){
pre = Math.max(pre+x, x);
maxAns = Math.max(maxAns, pre);
}
System.out.println(maxAns);
}
class Solution:
def cross_sum(self, nums, left, right, p):
if left == right:
return nums[left]
left_subsum = float('-inf')
curr_sum = 0
for i in range(p, left - 1, -1):
curr_sum += nums[i]
left_subsum = max(left_subsum, curr_sum)
right_subsum = float('-inf')
curr_sum = 0
for i in range(p + 1, right + 1):
curr_sum += nums[i]
right_subsum = max(right_subsum, curr_sum)
return left_subsum + right_subsum
def helper(self, nums, left, right):
if left == right:
return nums[left]
p = (left + right) // 2
left_sum = self.helper(nums, left, p)
right_sum = self.helper(nums, p + 1, right)
cross_sum = self.cross_sum(nums, left, right, p)
return max(left_sum, right_sum, cross_sum)
def maxSubArray(self, nums: 'List[int]') -> 'int':
return self.helper(nums, 0, len(nums) - 1)
方法2:贪心
算法:
该算法通用且简单:遍历数组并在每个步骤中更新:
当前元素
当前元素位置的最大和
迄今为止的最大和
class Solution:
def maxSubArray(self, nums: 'List[int]') -> 'int':
n = len(nums)
curr_sum = max_sum = nums[0]
for i in range(1, n):
curr_sum = max(nums[i], curr_sum + nums[i])
max_sum = max(max_sum, curr_sum)
return max_sum
方法3:动态规划(Kadane 算法)
常数空间,沿数组移动并在原数组修改。
def maxSubArray(nums):
n = len(nums)
max_sum = nums[0]
for i in range(1, n):
if nums[i-1]>0:
nums[i] += nums[i-1]
max_sum = max(nums[i], max_sum)
return max_sum
nums = [-1,2,3,5,3,-9]
s = maxSubArray(nums)
print(s)
给定一个排序数组,你需要在 原地 删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。
不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。
def removeDuplicates(nums):
n = len(nums)
if n == 0:
return 0
l = 0
for r in range(1, n):
if nums[r] != nums[l]:
l += 1
nums[l] = nums[r]
return l + 1
nums = [-1,2,3,5,3,-9]
s = removeDuplicates(nums)
print(s)
给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。
你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。
示例:
给定 nums = [2, 7, 11, 15], target = 9
因为 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]
java解法:
public static void main(String[] args) {
int[] nums = new int[]{12, 36, 19, 1, 25, 48, 22, 87, 92};
int[] s = twoSum(nums, 68);
if(s!=null) {
System.out.println(Arrays.toString(s));
}
}
// 暴力解法
public static int[] twoSum(int[] nums, int target){
for(int i=0; i<nums.length-1; i++){
for(int j=i+1; j<nums.length; j++){
if(nums[i]+nums[j] == target){
return new int[]{nums[i], nums[j]};
}
}
}
return null;
}
// 先排序,定义左右指针
public static int[] twoSum(int[] nums, int target){
Arrays.sort(nums);
int i =0;
int j = nums.length-1;
while (true) {
if(i>=j){
return null;
}
if (nums[i]+nums[j]==target)
return new int[]{nums[i], nums[j]};
if(nums[i]+nums[j] < target) {
i++;
continue;
}
if(nums[i]+nums[j] > target) {
j--;
continue;
}
}
}
// 建立hashMap映射(面试写法)
public static int[] twoSum(int[] nums, int target){
Map<Integer, Integer> map= new HashMap<>();
for(int i=0; i<nums.length; i++){
map.put(nums[i], i);
}
for(int i =0; i<nums.length; ){
int t = target - nums[i];
if(map.containsKey(t) && map.get(t) != i){
return new int[]{nums[i], t};
}
}
return null;
}
// 建立hashMap映射,合并两个for(没有排序,先找到哪个值都可以)
public static int[] twoSum(int[] nums, int target){
Map<Integer, Integer> map= new HashMap<>();
for(int i =0; i<nums.length; i++){
int t = target - nums[i];
if(map.containsKey(t) && map.get(t) != i){
return new int[]{nums[i], t};
}
map.put(nums[i], i);
}
return null;
}
python解法
// 建立hashMap映射
class Solution(object):
def twoSum(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: List[int]
"""
hashmap = {}
for k, v in enumerate(nums):
hashmap[v] = k
for k,v in enumerate(nums):
j = hashmap.get(target-v)
if j is not None and j != k:
return [k, j]
比较相邻的两个元素,如果第一个比第二个大就交换位置,循环完一遍最后的位置就是最大值。依次类推
时间复杂度O(n^2)
稳定性:稳定
def test(n):
m = len(n)
for i in range(m-1):
for j in range(m-i-1):
if n[j] > n[j+1]:
n[j], n[j+1] = n[j+1], n[j]
print(n)
a = [8,7,6,5,3,4,2,1]
test(a)
排序效果:
[7, 6, 5, 3, 4, 2, 1, 8]
[6, 5, 3, 4, 2, 1, 7, 8]
[5, 3, 4, 2, 1, 6, 7, 8]
[3, 4, 2, 1, 5, 6, 7, 8]
[3, 2, 1, 4, 5, 6, 7, 8]
[2, 1, 3, 4, 5, 6, 7, 8]
[1, 2, 3, 4, 5, 6, 7, 8]
def bubbleSort(nums):
l = len(nums)
k = l-1
# 记录最小值的位置
n = 0
for i in range(l-1):
# 记录交换元素的位置
pos = 0
# 记录交换元素的次数
flag = 0
# 遍历找到最大值
for j in range(n, k):
if nums[j] > nums[j+1]:
nums[j], nums[j+1] = nums[j+1], nums[j]
# 只要有交换元素,flag就设置为1
flag = 1
# 每次有元素交换,就记录最后一次交换的位置
pos = j
# 如果没有交换元素,说明已经排序
if flag == 0:
return
# pos之后的元素已排好序,不需要再遍历
k = pos
# 反向遍历找到最小值
for j in range(n+1, k):
if nums[j] < nums[j-1]:
nums[j], nums[j-1] = nums[j-1],nums[j]
flag =1
n += 1
if flag ==0:
return
nums = [1,2,3]
bubbleSort(nums)
print(nums)
先找最小值放到第一个位置,找第二个小值放到第二个位置,依次类推。
时间复杂度O(n^2),不稳定
def test(alist):
# 将最小的最放在最前面
length = len(alist)
for i in range(length-1):
temp = i
for j in range(i+1, length):
if alist[j] < alist[temp]:
temp = j
alist[i], alist[temp] =alist[temp], alist[i]
return alist
alist = [4,6,5,7,3,2,1]
print(test(alist))
排序效果:
[1, 6, 5, 7, 3, 2, 4]
[1, 2, 5, 7, 3, 6, 4]
[1, 2, 3, 7, 5, 6, 4]
[1, 2, 3, 4, 5, 6, 7]
[1, 2, 3, 4, 5, 6, 7]
[1, 2, 3, 4, 5, 6, 7]
假设前面是值是有序列表,将后面的值插到前面的有序列表中,依次类推
时间复杂度O(n^2) ,稳定性:稳定
def insert_sort(a):
for i in range(1, len(a)):
for j in range(i, 0, -1):
if a[j] < a[j - 1]:
a[j],a[j-1] = a[j-1],a[j]
else:
break
print(a)
a = [4,6,5,7,2,5,2]
insert_sort(a)
排序效果:
[4, 6, 5, 7, 2, 5, 2]
[4, 5, 6, 7, 2, 5, 2]
[4, 5, 6, 7, 2, 5, 2]
[2, 4, 5, 6, 7, 5, 2]
[2, 4, 5, 5, 6, 7, 2]
[2, 2, 4, 5, 5, 6, 7]
希尔排序是插入排序的改进版。
def shell_sort(alist):
n = len(alist)
# gap 是间隔
gap = n//2
while gap > 0 :
# 插入算法
for i in range(gap, n):
j= i
while j>0:
if alist[j] <alist[j-gap]:
alist[j],alist[j-gap] = alist[j-gap],alist[j]
else:
break
gap = gap//2
a = [1,3,2,65,32,54,87]
shell_sort(a)
print(a)
找出序列中的第一个值,判断这个值在序列中的位置。判断方法这个值前的元素都比这个值小,这个值后的元素都比这个值大。依次类推
最优时间复杂度:O(nlogn),最坏时间复杂度O(n^2),不稳定
def quick_sort(alist, start, end):
# 只有一个元素时不执行
if start >= end:
return
mid_value = alist[start]
low = start
high = end
while low < high:
# high游标左移
while low < high and alist[high] >= mid_value:
high -= 1
alist[low] = alist[high]
# low游标右移
while low < high and alist[low] < mid_value :
low += 1
alist[high] = alist[low]
# 找到元素的位置并放置
alist[low] = mid_value
# 对Low左边的列表进行排序
quick_sort(alist, start, low-1)
# 对Low右边的列表进行排序
quick_sort(alist, low+1, end)
a = [78,67,111,8,112,70,45]
quick_sort(a,0,len(a)-1)
print(a)
时间复杂度O(nlogn),稳定性:稳定
def merge_sort(alist):
n = len(alist)
if n <=1:
return alist
mid = n//2
# left 采用归并排序后生成新的列表
left_li = merge_sort(alist[:mid])
# right 采用归并排序后生成新的列表
right_li = merge_sort(alist[mid:])
# 将两个列表排序后合并成新的列表
left_pointer, right_pointer = 0, 0
result = []
while left_pointer < len(left_li) and right_pointer < len(right_li):
if left_li[left_pointer] > right_li[right_pointer]:
result.append(right_li[right_pointer])
right_pointer += 1
else:
result.append(left_li[left_pointer])
left_pointer += 1
result += left_li[left_pointer:]
result += right_li[right_pointer:]
return result
a = [11,32,43,12,5,38,34]
rs = merge_sort(a)
print(rs)
前提:列表有序,时间复杂度O(logn)
def binary_search(alist, item):
n = len(alist)
if n <= 0:
return False
mid = n//2
if item == alist[mid]:
return True
if item <alist[mid]:
return binary_search(alist[:mid], item)
elif item > alist[mid]:
return binary_search(alist[mid+1:], item)