赞
踩
目录
1、找一个数组中出现奇数次的那个数,要求时间复杂度O(N),空间复杂度O(1)
9、找出来数组中每个元素后边第一个比它大的值,要求复杂度为O(n)
延伸: 除了一个数出现了一次,其他数字出现了两次,找出这个出现了一次的数(异或)
方法取巧,0 跟数组里的数异或
参考:检测一个数组里面出现次数为奇数的数字_JULIUS_0的博客-CSDN博客
方法:异或运算为基础 , 偶数个一样的数异或为0, 0 和任何数异或,都是这个数本身,异或符合交换律 ,所以只需要把所有数组中所有数字异或一次就可以了
- int findIt(int[] A) {
- int xor = 0;
- for (int i = 0; i < A.length; i++) {
- xor = xor^A[i];
- }
- return xor;
- }
- void reversech(int[] num)
- {
- int len = num.length()
- //把第一个与最后一个交换;
- for (int i=0; i< len/2; ++i)
- {
- int temp = ch[i];
- num[i] = ch[len-1-i];
- num[len-1-i] = temp;
- }
- }
假设,这两个数组已经排好序(升序),那么只需要遍历一次即可。
首先设两个下标,分别初始化为两个数组的起始地址,依次向前推进 。推进的规则是比较两个数组中的数字,小的那个数组的下标向前推进一步,直到任何一个数组的下标到达数组末尾时,如果这时还没碰到相同的数字,说明数组中没有相同的数字
- void findcommon2(int a[], int size1, int b[], int size2)
- {
- int i=0,j=0;
- vector<int> vec;
-
- while(i<size1 && j<size2)
- {
- if(a[i]==b[j])
- {
- vec.push_back(a[i]);
- i++;
- j++;
- }
- if(a[i]>b[j])
- j++;
-
- if(a[i]<b[j])
- i++;
- }
- }

一左一右两个指针,遇到正负数不符合的交换位置
- void fun(int[] arr){
- int left = 0,right = arr.length-1;
- while(left < right){
- while(arr[left] % 2 == 1 && left < right){
- left++;
- }
- while(arr[right] % 2 == 0 && left < right){
- right--;
- }
- if(left < right){
- swap(arr,left,right);
- }
- }
- }
一个数组,数组中有正数和负数,重新排列这个数组,使得原始数组中的正负数交替排列,且保证各自的相对顺序不变。
- void fun1(int[] arry) {
-
- for(int i=0; i <= arry.length; i++)
- {
-
- if(i % 2 == 0 && arry[i] > 0) //判断所在位置应该是正数
- continue;
- else
- {
- // 不是正数,则查找第一个正数,交换
- for(int j=i+1; j<arry.length; j++)
- {
- if(arry[j] > 0) {
- swap(arry[i], arry[j]);
- break;
- }
- }
- }
-
- if(i % 2 == 1 && arry[i] < 0) //判断所在位置应该是负数
- continue;
- else
- {
- for(int j=i+1; j<arry.length; j++)
- {
- if(arry[j] < 0) {
- swap(arry[i], arry[j]);
- break;
- }
- }
- }
-
- }
- }

一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0。请你找出所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。
- public List<List<Integer>> threeSum(int[] nums) {
-
- nums = sort(nums) //先排序
- int n = nums.length;
-
- List<List<Integer>> res = new LinkedList<>();
-
-
- for (int i = 0; i < n - 2; i++) {
- if (nums[i] > 0) break; // 第一个数大于 0,后面的数都比它大,肯定不成立了
-
- // 去掉重复情况,如果两个数字相同,我们直接跳到下一个循环。
- if (i > 0 && nums[i] == nums[i - 1]) {
- continue;
- };
- int left = i + 1; // 左边的第一个数
- int right = n - 1; // 右边的最后一个数字
-
- // num[i] 是第一个数,则我们要动态寻找的另外两个数的和应该是 nums[left] + nums[right] = -nums[i]
- int target = -nums[i]
-
- while (left < right) {
-
- if (nums[left] + nums[right] > -nums[i])
- right--; // 两数之和太大,右指针左移
- else if (nums[left] + nums[right] < -nums[i])
- left++; // 两数之和太小,左指针右移
- else if (nums[left] + nums[right] == -nums[i])
- {
- // 找到一个和为零的三元组,添加到结果中,左右指针内缩,继续寻找
- res.push_back(vector<int>{nums[i], nums[left], nums[right]});
-
- // 现在要增加 left,减小 right,但是不能重复(第二个数和第三个数也不重复选取),
- // 比如: [-2, -1, -1, -1, 3, 3, 3], i = 0, left = 1, right = 6, [-2, -1, 3] 的答案加入后,需要排除重复的 -1 和 3
-
- left++; // 先进行加减操作
- right--;
-
- // 然后去重, 上面已经对index做了加减操作,所以left 要跟left-1比较, right 要跟 right+1 比较
- while (left < right && nums[left] == nums[left-1]) left++;
- while (left < right && nums[right] == nums[right+1]) right--;
- }
- }
- }
- return res;
- }

LeetCode:
解法1: 力扣
解法2:力扣
通常解法:双指针 leetcode笔记--633.判断给定的数是否为两个数平方的和_Eunice_Qiu的博客-CSDN博客
归纳法和动态规划解法:LintCode 697: 判断是否为平方数之和 -- O(n) 解法_Andrew Yang的博客-CSDN博客
遍历数组的所有元素一次:O(n)
对于访问的每个元素,检查它的key是否已存在于HashMap
如果它没有(第一次看到这个元素),那么把它添加到你的HashMap中[key:this element,value:1]。
如果确实存在,则将与该键对应的值递增 1
完成构建HashMap之后,遍历map并找到具有最高次数的元素 - 这是出现次数最多的元素。
部分代码解决方案,让你了解如何使用HashMap:
- int find(int[] arry) {
- HashMap hm = new HashMap();
- for (int i = 0; i < array.length; i++)
- {
-
- Double key = new Double(array[i]);
- if ( hm.containsKey(key) )
- {
- value = hm.get(key);
- hm.put(key, value + 1);
- }
- else
- {
- hm.put(key, 1);
- }
- }
- }

给一数组,找出数组中的众数,众数就是出现的次数超过一半的数
假设数组不为空,且众数一定存在
方法1:hashmap
通过遍历数组,将数组每个数都通过hashmap来统计其出现的个数,如果某个数个数超过一半,则为众数。
时间空间复杂度均为O(n)
方法2:Moore Voting Algorithm
众数存在的情况下,每次扔掉两个不同的数,众数不变,最终剩下的数一定是众数。
时间复杂度O(n),空间复杂度O(1)
摩尔投票算法:
先假设第一个元素为众数,计数器置为1,遍历数组,当遇到相同的元素时,计数器加1,否则减1,任何计算器为0的时候,就假设下一个元素为众数,计数器再置为1。循环结束时,返回我们假设的众数,即要求的众数。前提是存在众数即个数超过一半的数字
LeetCode:力扣
- // hash_map method
- int majorityElement1(vector<int> &num) {
- int n =num.size();
- if(n==1) return num[0];
- map<int,int> m;
- for(vector<int>::iterator it=num.begin();it!=num.end();it++){
- m[*it]+=1;
- if(m[*it] > floor(n/2))
- return *it;
- }
- return -1;
- }
-
- int majorityElement(int[] nums) {
- int len = nums.length;
- int count = 0;
-
- int value; // 众数
-
- for(int i = 0; i < len; i++){
- // 上一个循环 count 为0,则当次的 nums 设置为 众数 value,同时 count 设置为 1
- if(count == 0) {
- value = nums[i]
- count = 1;
- }
- else {
- // 两个值不相等,则扔掉这两个数, 相等则 计数加1
- if (value == nums[i]){
- count++;
- } else{
- count--;
- }
- }
- }
- return value;
- }

考察:回溯法
LeetCode:力扣
相似问题:
1、电话号码的字母组合: 力扣
2、组合总和:LeetCode: 力扣
-
- void persort(int[] arr,int start)
- {
- //start代表从arr中的第几个数开始
- //当start==arr.length-1时,说明子序列的长度为1,就不用再往下分子序列了
- if(start==arr.length-1)
- {
- for(int i=0 ;i<=m ;i++)
- cout<<list[i];
- cout<<endl;
- }
- for(int i=start;i<arr.length;i++)
- {
- //start代表的是每一个子序列的第一个位置,我们每一层递归的任务都只有一个:
- //枚举该层子序列第一个位置可以取的值
- int temp=arr[start];
- arr[start]=arr[i];
- arr[i]=temp;
-
- //该层递归的子序列第一个位置已经确定了,所以又可以往下再分
- persort(arr,start+1);
-
- //把第该层子序列第一个位置的值换成另外一个值,所以要交换回来
- temp=arr[start];
- arr[start]=arr[i];
- arr[i]=temp;
- }
- }

全排列相关:1、一个简单的全排列算法_GetterAndSetter的博客-CSDN博客_全排列算法
2、全排列(递归算法)_MsStrbig的博客-CSDN博客_全排列
如数组A=[6,8,9,2,3,5,6] 输出[8,9,-1,3,5,6,-1]
思路:
我们用栈来保存未找到右边第一个比它大的元素的索引(后面要用索引来给res数组赋值)步骤如下:
对于当前遍历的第i个元素有:
1. 栈为空,则当前索引i入栈, 同时说明前面的元素都找到了右边比它大的元素
2. 栈不为空,如果栈顶索引元素大于等于当前元素,则将当前索引i入栈;(目的是为了保持栈从栈底到栈顶非升序)
3. 栈不为空,当前元素大于栈顶索引元素,则栈顶索引元素对应的第一个比它大的元素就是当前元素,保存当前元素;同时为了保证栈底到栈顶非升序需要将栈顶元素弹出,
4. 循环判断1、2、3条件,直到满足1、2条件。
5. 输入遍历完,栈中还剩余的元素则是不能找见之后比他大的元素。
遍历完所有元素,如果栈不为空,说明栈中保存的全是未找到右边第一个比它大的数组索引,我们依次将这些栈元素出栈,并赋值result[stack.pop()] = -1即可。
问题分析:利用单调栈,从左至右依次压入数据的索引(若直接压数,则还需要一个数组保存栈中元素所对应的数组位置),如果当前元素小于等于栈顶的索引所对应的数组的值,入栈当前索引,否则将栈顶索引出栈,并在栈顶索引所对应的res数组中记录下当前的值。到最后再检查栈中剩余元素,代表剩余元素右边没有比它大的值,在res对应位置赋值为-1。
- void findNearestMax(int *arr,int n,int *res) {
- int i = 0;
- stack<int> s; // 存放id
- //开辟一个新空间,存放结果
- int *res= new int[arr.length];
-
- while (i < n) {
-
- // 条件 1 和 条件2 的判断
- if (s.empty() || arr[s.top()] >= arr[i])
- s.push(i++);
- else
- {
- //这个判断里面,当找到的 arr[i] > arr[s.top()],则将栈s.top出栈,
- // 同时将 res中 索引为 s.top() 的元素值改成,arr[i],
- //但是 i 没有改变,继续判断该元素arr[i]是否还大于栈里面的其他元素
- //直到找不满足上述条件则将该元素id入栈
-
- res[s.top()] = nums[i];
- s.pop();
- }
- }
- // 剩下的则是没有找到比该元素大的数
- while (!s.empty()) {
- res[s.top()] = -1;
- s.pop();
- }

剑指Offer 29、最小的K个数 :【剑指Offer】29、最小的K个数 - gzshan - 博客园
LeetCode:力扣
- vector<int> quickSort(vector<int>& arr, int k, int l, int r) {
- int i = l, j = r;
- while (i < j) {
- while (i < j && arr[j] >= arr[l]) j--;
- while (i < j && arr[i] <= arr[l]) i++;
- swap(arr[i], arr[j]);
- }
- swap(arr[i], arr[l]);
- if (i > k) return quickSort(arr, k, l, i - 1);
- if (i < k) return quickSort(arr, k, i + 1, r);
- vector<int> res;
- res.assign(arr.begin(), arr.begin() + k);
- return res;
- }
- 数组求第k小数字的下标
思路解析(代码有问题)
1、最暴力的思想,直接排序,然后索引第k个数据,最优的排序算法时间复杂度为O(nlog(n)),但是随着n的变大,复杂度增长
2、借助快速排序的思想
快速排序的思想是通过一趟排序将要排序的list分为2部分,左边小,右边大。然后递归排序左右。我们可以在每一趟排序后,比较基准元素的索引和K的大小,若k大于基准元素的索引,则要寻找的k大数字就在基准元素的右边,否则左边。直到找到基准元素的索引等于K。时间复杂度 O(n)
3、堆排序,查看LeetCode中得讲解
求第k大相当于求第n-k+1小,n为数组长度。 或者 快排时候左边是大数右边是小数。下面展示第K小
- int quick_sort( int[] arry, int left, int right ) {
-
- int value = arry[left]; #拿出第一个数当作基准数value
- int low = left; #low来标记左侧从基准数始找比value大的数的位置
- int high = right; #high来标记右侧right向左找比value小的数的位置
-
- # 我们要进行循环,只要low和high没有碰头就一直进行,当low==high说明碰头了
- while (low < high) {
-
- while(low < high && arry[high] > value ) {
- high--;
- }
- while(low < high && arry[low] <= value ) {
- low--;
- }
- swap(arry[low], arry[high]);
- }
-
- # 基准元素归位
- arry[left] = arry[low];
- #当这个while跳出来之后相当于low==high碰头了,我们把index的数值放在这个空位
- arry[low] = value;
-
- #这个时候index左侧看的数都比index小,index右侧的数都比index大
- return low
- }
-
- int find_k(int[] arry, int k) {
-
- int n = len(arry);
- int left = 0;
- int right = n-1;
- int index = partition(arry,left,right);
- while (index != k) {
- if (index>k) {
- right = index-1;
- index = quick_sort(arry,left,right);
- }
- else {
- left = index+1;
- index = quick_sort(arry,left,right);
- }
- }
-
- return arry[k]
- }

堆排序:
LeetCode:力扣
分析:
解法一:游标计数
题目只要求第k大的数,没必要花力气将数组全部再排序,可以定义两个游标分别指向两个有序数组,按序移动,并用count计数,当count等于k时,返回两个游标指向的数中最小的那一个
时间复杂度O(m+n),空间复杂度O(m+n)
- int find_Kth( int* array1, int len1, int* array2, int len2, int K )
- {
- if(!array1||!array2||len1==0||len2==0)
- return -1;
- int i = 0;
- int j = 0;
- int count = 0;
-
- while( count<K-1 )
- {
- if( array1[i]<=array2[j] )
- i++;
- else
- j++;
- count++;
- }
- return array1[i]>=array2[j]?array2[j]:array1[i];
- }

二分法:
有没有更好的方案呢?我们可以考虑从 k 入手。如果我们每次都能够删除一个一定在第 k 大元
素之前的元素,那么我们需要进行 k 次。但是如果每次我们都删除一半呢?由于 A 和 B 都是有序
的,我们应该充分利用这里面的信息,类似于二分查找,也是充分利用了“有序” 。
假设 A 和 B 的元素个数都大于 k/2,我们将 A 的第 k/2 个元素(即 A[k/2-1])和 B 的第 k/2
个元素(即 B[k/2-1])进行比较,有以下三种情况(为了简化这里先假设 k 为偶数,所得到的结
论对于 k 是奇数也是成立的) :
• A[k/2-1] == B[k/2-1]
• A[k/2-1] > B[k/2-1]
• A[k/2-1] < B[k/2-1]
如果 A[k/2-1] < B[k/2-1],意味着 A[0] 到 A[k/2-1] 的 k/2 个元素肯定在 A ∪ B 的 top k 元素的范围
内,换句话说,A[k/2-1]不可能大于 A ∪ B 的第 k 大元素
因此,我们可以放心的删除 A 数组的这 k/2 个元素。同理,当 A[k/2-1] > B[k/2-1] 时,可
以删除 B 数组的 k/2 个元素。
当 A[k/2-1] == B[k/2-1] 时,说明找到了第 k 大的元素,直接返回 A[k/2-1] 或 B[k/2-1]
即可。
因此,我们可以写一个递归函数。那么函数什么时候应该终止呢?
• 当 A 或 B 是空时,直接返回 B[k-1] 或 A[k-1];
• 当 k=1 是,返回 min(A[0], B[0]);
• 当 A[k/2-1] == B[k/2-1] 时,返回 A[k/2-1] 或 B[k/2-1]
比较简单的情况:假设 A 和 B 的元素个数都大于 k。则不存在 A、B为空的情况:
- def Binary_find_Kth(self, arrayA,arrayB,k):
- m = len(arrayA)
- n = len(arrayB)
- # 保持让arrayA的长度最小
- if m > n:
- return self.Binary_find_Kth(arrayB,arrayA,k)
- if m == 0:
- return arrayB[k-1]
- if k == 1 :
- return min(arrayA[0],arraybB[0])
-
- # 将k分成两部分,一部分在arrayA上,一部分在arrayB上
- # 保证 k1 + k1 = k
- k1 = k // 2
- k2 = k - k1
-
- if arrayA[k1-1] > arrayB[k2-1]:
- return Binary_find_Kth(arrayA,arrayB[k2:],k-k2)
- # 由于题目说了没有交集,这里不考虑相等情况
- elif arrayA[k1-1] < arrayB[k2-1]:
- return Binary_find_Kth(arrayA[k1:],arrayB,k-k1)
- else arrayA[k1-1] == arrayB[k2-1]:
- return arrayA[k1-1]

2、全面考虑数组长度和 k 的大小
-
- /*在两个升序排序的数组中找到第k大的元素*/
- int Binary_find_Kth(int* array1, int len1, int* array2,int len2, int k)
- {
- if( k < 0 )
- {
- cout<<"Invalid k = "<<k<<endl;
- return -1;
- }
- // 在这里始终保证 len1 <= len2
- if( len1 > len2 )
- return Binary_find_Kth(array2,len2, array1,len1, k);
- if( len1 == 0 )
- return array2[k-1];
- if( k == 1)
- return ((array1[0]>= array2[0]) ? array2[0] : array1[0]);
-
- // 不一定每个数组都有k/2个元素,上面保证了, len1 < len2
- int k1 = min(k/2, len1)
- int k2 = k - k1;
-
- /**
- 说明array2的k2-1前部分一定在第k大元素之前,因此:
- 1)将k2-1这部分全跳过:更新数组首位地址索引,同时更新数组长度;
- 2)将这k2元素纳入已找到的第k大元素范围内,更新k值:k-k2
- **/
-
- if( array1[k1-1] > array2[k2-1] )
- {
- return Binary_find_Kth(array1, len1, &array2[k2], len2-k2, k-k2);
- }
-
- /**
- 说明array1的k1-1前部分一定在第k大元素之前,因此:
- 1)将k1-1这部分全跳过:更新数组首位地址索引,同时更新数组长度;
- 2)将这k1元素纳入已找到的第k大元素范围内,更新k值:k-k1
- **/
-
- else if( array1[k1-1] < array2[k2-1] )
- {
- return Binary_find_Kth(&array1[k1], len1-k1, array2, len2, k-k1);
- } else if( array1[k1-1] == array2[k2-1] )
- return array1[k1-1];
- }

寻找数组中的中位数,不能排序(用最大堆加最小堆可解决)
思路按照求第K小的思路实现
LeetCode: 力扣
LeetCode: 力扣
(LeetCode287)给定一个包含 n + 1 个整数的数组 nums,其数字都在 1 到 n 之间(包括 1 和 n),可知至少存在一个重复的整数。假设只有一个重复的整数,找出这个重复的数。
要求:
1、不能更改原数组(假设数组是只读的)。
2、只能使用额外的 O(1) 的空间。
3、时间复杂度小于 O(n2) 。
4、数组中只有一个重复的数字,但它可能不止重复出现一次。
思路:快慢指针原理简易解释
使用数组中的值作为索引下标进行遍历,遍历的结果肯定是一个环(有一个重复元素)
检测重复元素问题转换成检测环的入口
为了找到环的入口,可以进行如下步骤:
1、设置两个快慢指针, fast每次走两步,slow每次走一步,最终走了slow走了n步与fast相遇,fast走了2*n,fast可能比slow多饶了环的 i 圈,得到环的周长为 n/i (这个 i 不需要知道,只要知道相遇时 n 是 环的整数倍)(注意此时的n不是指数组的长度)
2、slow指针继续走, 且另设第三个指针从起点位置开始每次走一步,两个指针必定在入口处相遇
- int findDuplicate(vector<int>& nums) {
-
- int fast = 0, slow = 0;
- while(true){
- fast = nums[nums[fast]];
- slow = nums[slow];
- if(fast == slow)
- break;
- }
- int finder = 0;
- while(true){
- finder = nums[finder];
- slow = nums[slow];
- if(slow == finder)
- break;
- }
- return slow;
- }

解释:力扣
动态规划解法: n个整数,求其中任意n-1个数的乘积中的最大的一个(不准用除法)_皮皮go的博客-CSDN博客
给定一个长度为N的整数数组,只允许用乘法,不能用除法,计算任意(N-1)个数的组合中乘积最大的一组,并写出算法的时间复杂度。
法一:
时间空间复杂度都为O(n)
s1[i]:从前往后遍历 到 0到i-1 位置的乘积(0<=i<n)
s2[j]:从后往前遍历 i+1到n 位置的乘积(0<=j<n)
有Max={s[i]*t[i]}
最后遍历一遍找出 max 最大值
法二:
设这n个数的乘积为P
当P=0时,除去n个数中的一个0,计算剩下的数的乘积,记为Q:
当Q=0时,说明n个数中至少有两个0,不管怎么组合,n-1个数的乘积都为0
当Q>0时,说明n个数中只有一个0,此时的Q当然是所要的乘积最大的结果
当Q<0时,说明n个数中只有一个0,但是除去0剩下的数的积为负数,所以还不如把0留下让乘积结果为0
当P>0时,从n个数中剔除最小的正数后所得的n-1个数的乘积即为最大值
当P<0时,从n个数中剔除绝对值最小的负数后所得的n-1个数的乘积即为最大值
- /*方法1:
- s[i]表示0到i-1乘积,t[i]表示i+1到n乘积,有Max={s[i]*t[i]}
- */
- long caculate(int arr[],int length){
- long maxV=LONG_MIN;
- long *s=new long[length+1];
- long *t=new long[length+1];
- s[0]=1,t[length-1]=1;
- for(int i=1;i<=length;++i)
- s[i]=s[i-1]*arr[i-1];
- for(int i=length-2;i>=0;--i){
- t[i]=t[i+1]*arr[i+1];
- }
- for(int i=0;i<length;++i)maxV=max(maxV,s[i]*t[i]);
- delete[] s;
- delete[] t;
- return maxV;
- }
- /*方法2:
- 统计数组中正负零的个数
- */
- long caculate2(int arr[],int length){
- long multi=1; //结果
- bool flag=false; //标识,数组中去掉的只能是一个数
- int opt=0,neg=0,zero=0;//正负零的个数
- int minO=INT_MAX; //最小的正数
- int maxN=INT_MIN; //最大的负数
- for(int i=0;i<length;i++){
- if(arr[i]<0){
- neg++;
- maxN=max(maxN,arr[i]);
- } else if(arr[i]>0){
- opt++;
- minO=min(minO,arr[i]);
- }
- else {
- zero++;
- }
- }
-
- // 大于1个0
- if(zero>1) {
- return 0;
- }
-
- //1个0的情况
- if(zero==1){
- // 如果奇数个负数,最大是0
- if(neg%2 == 1) {
- return 0;
- }
- else{
- // 如果偶数个负数,则直接输出n-1个数乘积
- for(int i=0;i<length;++i)
- if(arr[i]!=0)
- multi*=arr[i];
- return multi;
- }
- }
-
- // 下面是没有0的情况
- //有奇数个负数,去掉最大的负数,即绝对值最小的负数
- if(neg%2 == 1){
- for(int i=0;i<length;++i){
- // flag 防止 重复数
- if(arr[i]!= maxN||flag){
- multi*=arr[i];
- }
- else flag=true;
- }
- return multi;
- }
- //有偶数个负数,去掉最小的正数
- for(int i=0;i<length;++i){
- if(arr[i]!=minO||flag){
- multi*=arr[i];
- }
- else flag=true;
- }
- return multi;
- }

分析查看:【剑指Offer】64、滑动窗口的最大值 - gzshan - 博客园
- public ArrayList<Integer> maxInWindows(int [] num, int size){
- /*
- 思路:用双端队列实现
- size window 大小
- queue.peek() 都是用来返回队列的头元素,不删除
- queue.poll() 从队列头部删除一个元素
- queue 中存放的是数组的index 方便计数
- queue 的长度不能大于 window 的size
- */
- ArrayList<Integer> res=new ArrayList<>();
- if(num==null || num.length<1 || size<=0 || size>num.length)
- return res;
- Deque<Integer> queue=new LinkedList<>();
- for(int i=0;i<num.length;i++){
-
- // 当加入第 i 个元素后,queue的长度为 (i-queue.peek() + 1)
- // 如果 (i-queue.peek() + 1) > size 时候,queue头元素,超出范围去掉
- while(!queue.isEmpty() && (i-queue.peek() + 1) > size)
- queue.poll();
- //当前值大于之前的值,之前的不可能是最大值,可以删掉
- while(!queue.isEmpty() && num[i]>=num[queue.getLast()])
- queue.removeLast();
- queue.add(i);
- // 数组从0开始,当 i=size-1 时,queue中正好有size个元素
- if(i>=size-1){ //此时开始是第一个滑动窗口
- res.add(num[queue.peek()]);
- }
- }
- return res;
- }

用队列做,需要看:面试题65. 滑动窗口的最大值_两鬓已不能斑白的博客-CSDN博客_滑动窗口的最大值
参考: https://www.cnblogs.com/debugxw/p/11461746.html
例如:a=[10,6,2,7,3],M=2,答案为16,两段分为[10,6][2,7,3]
问题描述
把一个包含n个正整数的序列划分成m个连续的子序列。设第i个序列的各数之和为S(i),求所有S(i)的最大值最小是多少?
例子:
序列1 2 3 2 5 4划分为3个子序列的最优方案为 1 2 3 | 2 5 | 4,其中S(1),S(2),S(3)分别为6,7,4,那么最大值为7;
如果划分为 1 2 | 3 2 | 5 4,则最大值为9,不是最小。
解题思路
我们对问题做一些转化:
在一次划分中,求一个x,使得x满足:对任意的S(i),都有S(i)<=x;这个条件保证了x是所有S(i)中的最大值。我们需要求的就是满足该条件的最小的x。
有了这个思路之后,我们继续分析如何找到这个x,首先,可以知道的是,max <= x <= sum。
接下来先是最朴素的想法:枚举每一个x,贪心地每次从左向右尽量多划分元素,但是S(i)不能超过x,而且划分的子序列个数不能超过m个(即所用划分线不能超过m-1条)
以上方法当然可行,但是每个x都遍历一次太浪费时间了。
问题经过转化,现在变成了在[max, sum]中间查找一个满足条件的x,查找的问题,相信大家对二分搜索并不陌生。这个时候,用二分搜索的思想来求x,效率一下子就上来了。
- int max = 数组元素中的最大值;
- int sum = 数组所有元素之和;
-
-
- int binary_solve()
- {
- int x=max; //要寻找的数
- int y=sum;
- while(x<y)
- {
- int findmin = x+(y-x)/2; //要查找的 --- 最大值的最小化
-
- //如果能找到满足条件的划分,则最小化的值在 x 和 findmin 之间,否则 在 findmin+1 和y之间
- if(is_part(findmin))
- {
- y=findmin; //如果找到
- }
- else
- {
- x=findmin+1; //不能划分,则在findmin+1 和y之间查找
- }
-
- }
- return x;
- }
-
- //是否能把序列划分为每个序列之和不大于x的m个子序列
- bool is_part(int x)
- {
- //每次往右划分,划分完后,所用的划分线不大于m-1个即可
- int line=0,s=0;
-
- for(int i=0;i<n;i++)
- {
- //假如有其中一个元素大于x,则极端地把划分线分别设在在其左边和右边,
- //都不能使这一个只有一个元素的序列之和不大于x,更不用说所有序列之和不大于x
- //如果 x 从 arry[maxn] 为初始值的话,就用不到这个判断了
- if(arry[i]>x)
- {
- return false;
- }
- // 如果和大于,就不能再把当前元素加上了 ,因此在arry[i-1],arry[i]之间做划分
- // arry[i] 就分到下一个分组了
- if(s+arry[i] > x)
- {
- line++; //此处多用了一条横杠
- s = arry[i]; //此时arry[i] 作为下一个分组的开始
- if(t>m-1) //t=m 时退出,即在最后一个元素之前都已经用了m条划分线,此时已把序列划分成了m+1个序列,太过分了,让其适可而止
- {
- return false;
- }
- }
- else
- {
- s+=arry[i];//把当前元素与前面的元素连上,以便尽量往右划分,贪心到底
- }
- }
- return true;
- }

求第n个丑数--coding_ytusdc的博客-CSDN博客
- /**
- * 二分查找,找到该值在数组中的下标,否则为-1
- */
- static int binarySerach(int[] array, int key) {
- int left = 0;
- int right = array.length - 1;
-
- // 这里必须是 <= “=” 时才能取到mid值
- while (left <= right) {
- int mid = (left + right) / 2;
- if (array[mid] == key) {
- return mid;
- }
- else if (array[mid] < key) {
- left = mid + 1;
- }
- else {
- right = mid - 1;
- }
- }
-
- return -1;
- }

每次移动left和right指针的时候,需要在mid的基础上+1或者-1, 防止出现死循环, 程序也就能够正确的运行。
二分查找及其变体:https://www.jianshu.com/p/d29603b4ed02
普通二分查找 :二分查找(Binary Search) - 程序员姜戈 - 博客园
[1,2,3,7,8,8,8,9]
解法:1、暴力法遍历数组就好
2、二分查找,因为有序,找到 pos 左右,从pos 开始左右遍历
- int binarySerach(int[] array, int key) {
- int left = 0;
- int right = array.length - 1;
-
- int pos;
-
- // 这里必须是 <= “=” 时才能取到mid值
- while (left <= right) {
- int mid = (left + right) / 2;
- if (array[mid] == key) {
- pos = mid;
- }
- else if (array[mid] < key) {
- left = mid + 1;
- }
- else {
- right = mid - 1;
- }
- }
-
- //上面是二分查找
-
- //最后一次出现的位置
- for(int i=pos; i<=right; i++) {
- if(array[i] == key)
- {
- pos = i;
- }
- else {
- return pos;
- }
- }
-
- // 第一次出现的位置
- for(int i=pos; i >=0; i--) {
- if(array[i] == key)
- {
- pos = i;
- }
- else {
- return pos;
- }
- }
- }

用两个队列实现一个栈的功能操作C++_YangXueChina的博客-CSDN博客_c++两个队列实现一个栈
这个解释比较清晰:
官方题解:力扣
- void dfs(char[][] grid, int r, int c) {
- int nr = grid.length;
- int nc = grid[0].length;
-
- // 判断坐标 (r, c) 是否在网格中
- if (r < 0 || c < 0 || r >= nr || c >= nc) {
- return;
- }
-
- // 如果这个格子不是岛屿,直接返回
- if( grid[r][c] != 1) {
- return;
- }
-
- grid[r][c] = '2'; // 将格子标记为「已遍历过」
- dfs(grid, r - 1, c);
- dfs(grid, r + 1, c);
- dfs(grid, r, c - 1);
- dfs(grid, r, c + 1);
- }
-
- public int numIslands(char[][] grid) {
- if (grid == null || grid.length == 0) {
- return 0;
- }
-
- int nr = grid.length;
- int nc = grid[0].length;
- int num_islands = 0;
- for (int r = 0; r < nr; ++r) {
- for (int c = 0; c < nc; ++c) {
- if (grid[r][c] == '1') {
- ++num_islands;
- dfs(grid, r, c);
- }
- }
- }
-
- return num_islands;
- }

在一个 n * m 的二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个高效的函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
思路:二维数组中,从左到右,从上到下是递增的,所以可以从将目标数从右上角开始遍历,如果当前数小于目标数,就向下遍历,如果当前数大于目标数就向左遍历。直到遍历完整个二维数组。
- public boolean findNumberIn2DArray(int[][] matrix, int target) {
- if(matrix==null||matrix.length==0||matrix[0].length==0){
- return false;
- }//如果二维数组为空,或者行数为0,或者列数为0,那么直接返回false
- int rows=matrix.length;//
- int cols=matrix[0].length;
- int r=0;//设置起始点,从右上角的第一个数开始遍历。
- int c=cols-1;//列下标比列数少1
- while(r<=rows-1 &&c>=0){//只要行下标不超过二维数组的行数,列下标不小于列数。
- if(matrix[r][c] == target){//如果找到目标值就返回true
- return true;
- }
- else if(matrix[r][c] < target){ //如果遍历到的数值比目标值小,就往下一行遍历
- r++;
- }
- else{//如果遍历的数值比目标值大,就往同一行中左边的列遍历。
- c--;
- }
- }
- return false;//遍历完整个二维数组之后没有找到目标值,说明目标值不在这个二维数字中,返回false。
- }

- 有一个长度为n的数组,元素都是[1, n]且无重复,这时随机删除一个元素,1)求删除元素,2)要求时间复杂度O(n),空间O(1),3)不能改变数组
1)用1+2+...+n减去当前输入数据的总和。时间复杂度:O(n) 空间复杂度:O(1) 【容易溢出】
2)用12...*n除以当前输入数据的总积。时间复杂度:O(n) 空间复杂度:O(1) 【容易溢出】
3)用1^2^...^n的结果在逐个异或当前输入数据。时间复杂度:O(n) 空间复杂度:O(1)
异或方法:
Y=1^2^3...^N,然后遍历数列每次异或当前的数字,最后剩下的就是要求的数字
任何数异或自己都等于0,任何数异或0都等于他自己
- public int find_Miss_Number_By_XOR(int array[]) {
- int result = 0;
-
- for (int i = 0; i < array.length; i++) {
- result = result ^ array[i];
- }
-
- int N = array.length;
- for (int i = 1; i <= N; i++) {
- result=result^(i);
- }
- return result;
-
- }
- vector<int> missingTwo(vector<int>& nums) {
- vector<int> res;
- //法二 分组求和
- int N = nums.size()+2;
- int sumN = 0,sumNum = 0,sumLess_Num=0,sumLess_N=0;
- for(auto num : nums)
- sumNum += num;
- for(int i=1;i<=N;i++)
- sumN += i;
- // sumTwo是两个数的和
- int sumTwo = sumN - sumNum;
- // 求两个数和的一半,那么两个缺失得数一个大于diff,一个小于diff。
- int diff = (sumTwo)/2;
- //针对 N 和sum两个数组,小于等diff的分别分为一组;大于diff的分别分为一组;那么两个组的差值即为缺失的一大一小
- for(auto num : nums){
- if(num<=diff){
- sumLess_Num += num;
- }
- }
-
- for(int i=1;i<=N;i++){
- if(i<=diff){
- sumLess_N += i;
- }
- }
- res.push_back(sumLess_N-sumLess_Num);
- res.push_back(sumTwo-(sumLess_N-sumLess_Num));
- return res;
- }

Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。