小浩算法-java题解(数组篇)


原文链接
https://www.geekxh.com/0.0.%E5%AD%A6%E4%B9%A0%E9%A1%BB%E7%9F%A5/01.html
这里是把这个大佬的题解用java写一下做个记录

数组系列

两个数组的交集(350)

给定两个数组,编写一个函数来计算它们的交集。

示例 1:
输入: nums1 = [1,2,2,1], nums2 = [2,2]
输出: [2,2]

方法一:map映射
两组数记录下每组数中每位数的次数,再加入另一组数中比较,如果另一组数组的元素在map中的v,也就是次数大于0,做记录,如果次数=0除去这个数。注意要减次数。
官方题解比较美观,贴出来。

class Solution {
    public int[] intersect(int[] nums1, int[] nums2) {
          if(nums1.length>nums2.length)
           return intersect(nums2,nums1); //保证nums1永远是那个最小的
    
    Map<Integer,Integer> map=new HashMap<Integer,Integer>();
   for (int num : nums1) 
    {
        int count=map.getOrDefault(num,0)+1; //如果出现过出现次数+1,如果没出现过为1
        map.put(num,count);
    }
    int [] intersection=new int[nums1.length];//记录结果的,最大长度是nums1的长度
    int index=0;
    for(int num:nums2)
    {
        int count=map.getOrDefault(num,0);
        if(count>0)
        {
            intersection[index++]=num;
            count--;//记录完记得减次数
            if(count>0)//减完还是大于0更新map
            {
                map.put(num,count);
            }else//=0说明该移除了
            {
                map.remove(num);
            }
        }
    }
    return Arrays.copyOfRange(intersection,0,index); 
}
}

方法二:排序后双指针对比,碰到一样的记录,不一样的根据大小往后推,直到两边都遍历完,用一个ans数组存储结果。

class Solution {
    public int[] intersect(int[] nums1, int[] nums2) {
       if(nums1.length>nums2.length)
       return intersect(nums2,nums1);

       int ans[]=new int[nums1.length];
       Arrays.sort(nums1);
       Arrays.sort(nums2);
       int i=0,j=0,k=0;
       while(i<nums1.length && j<nums2.length)
       {
           if(nums1[i]==nums2[j])
            {
                ans[k++]=nums1[i];
                i++;j++;
            }else if(nums1[i]>nums2[j])
            {
                j++;
            }else i++;
       }
       return Arrays.copyOfRange(ans, 0, k);
}
}

最长公共前缀

编写一个函数来查找字符串数组中的最长公共前缀。如果不存在公共前缀,则返回""

示例1:

输入: ["flower","flow","flight"]
输出: "fl"

解题思路:横向比较,假设第一个就是答案,向后遍历,遍历时判断这两个的公共前缀,如果出现了空的就直接返回“”,否则继续向后。
参考:https://leetcode-cn.com/problems/longest-common-prefix/solution/hua-jie-suan-fa-14-zui-chang-gong-gong-qian-zhui-b/

class Solution {
    public String longestCommonPrefix(String[] strs) {
             if(strs.length==0) return "";
             String prefix=strs[0];
             for(int i=1;i<strs.length;i++)
             {
                 int j=0;
                 for(;j<prefix.length() && j<strs[i].length();j++)//j是要小于两个才是公共前缀
                 {
                         if(prefix.charAt(j)!=strs[i].charAt(j))
                         break;
                 }
                 prefix=prefix.substring(0,j);
                 if(prefix.equals("")) return "";
             }
             return prefix;
    }
}

第122题:买卖股票的最佳时机 II

给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。
如果你最多只允许完成一笔交易(即买入和卖出一支股票),设计一个算法来计算你所能获取的最大利润。注意你不能在买入股票前卖出股票。

示例 1:
输入: [7,1,5,3,6,4]
输出: 7
解释: 在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。
随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6-3 = 3 。

贪心:只算正数的

class Solution {
    public int maxProfit(int[] prices) {
        int ans=0;
        int tem_ans=0;
        for(int i=1;i<prices.length;i++)
        {
            tem_ans=prices[i]-prices[i-1];
            if(tem_ans>0)
                ans+=tem_ans;
        }
        return ans;
    }
}

题目189: 旋转数组

给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数。
示例 1:

输入: [1,2,3,4,5,6,7] 和 k = 3
输出: [5,6,7,1,2,3,4]
解释:

向右旋转 1 步: [7,1,2,3,4,5,6]
向右旋转 2 步: [6,7,1,2,3,4,5]
向右旋转 3 步: [5,6,7,1,2,3,4]

解题思路:反转数组,7654321,再分别反转 k%7,得到答案。

class Solution {
    public void rotate(int[] nums, int k) {
          reverse(nums,0,nums.length-1);
          k%=nums.length; //如果k的长度大于数组长度,那么只计算取余之后的,因为=的部分会不变。
          reverse(nums,0,k-1);
           reverse(nums,k,nums.length-1);
          
    }
    public void reverse(int [] nums,int strat,int end)
    {
         while(strat<end)
        {
            int tem=nums[strat];
            nums[strat]=nums[end];
            nums[end]=tem;
            end--; strat++;
        }
    } 
}

题目27:移除元素

给定一个数组 nums 和一个值 val,你需要原地移除所有数值等于 val 的元素,返回移除后数组的新长度。
不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。

元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。

示例 1:

给定 nums = [3,2,2,3], val = 3,
函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。
你不需要考虑数组中超出新长度后面的元素。

解题思路:修改后必定是长度少于原来的,我们直接修改。

class Solution {
    public int removeElement(int[] nums, int val) {
        int k=0; //这个就是真正的索引
        for(int i=0;i<nums.length;i++)
        {
            if(nums[i]!=val)
            {
                nums[k]=nums[i];
                k++;
            }
        }
        return k;
    }
}

类似题目:删除排序数组中的重复项

给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次。
返回移除后数组的新长度。不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。

示例 1:

给定数组 nums = [1,1,2],
函数应该返回新的长度 2, 并且原数组 nums 的前两个元素被修改为 1, 2。
你不需要考虑数组中超出新长度后面的元素。

解题思路:和上面的类似,稍作修改,还是用一个真正的索引来确定位置,然后进行判断。

class Solution {
    public int removeDuplicates(int[] nums) {
       if(nums.length==0)return 0;
       int index=1;
        for(int i=1;i<nums.length;i++)
        {
            if(nums[i]!=nums[i-1])
            {
                nums[index]=nums[i];
                index++;
            }
        }
        return index;
    }
}

删除排序数组中的重复项 II

给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素最多出现两次,返回移除后数组的新长度。

不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。

示例 1:

给定 nums = [1,1,1,2,2,3],

函数应返回新长度 length = 5, 并且原数组的前五个元素被修改为 1, 1, 2, 2, 3 。

你不需要考虑数组中超出新长度后面的元素。

解题思路:已经排好序,我们直接看第三个是不是和第一个一样,不一样我们更新数组,一样就不更新

class Solution {
    public int removeDuplicates(int[] nums) {
        int i=0;
        for(int n:nums)
            if(i<2|| n!=nums[i-2])
                nums[i++]=n;
        return i;
    }
}

第66题:加一

给定一个由整数组成的非空数组所表示的非负整数,在该数的基础上加一。
最高位数字存放在数组的首位, 数组中每个元素只存储单个数字。你可以假设除了整数 0 之外,这个整数不会以零开头。

示例 1:

输入: [1,2,3]
输出: [1,2,4]
解释: 输入数组表示数字 123。

解题思路:从后往前看,普通情况就是加上之后不会进位直接输出即可,特别情况下进位,然后输出即可,再更特别情况下要一直进位,还要在前面补个一。
贴个神仙思路:https://leetcode-cn.com/problems/plus-one/solution/java-shu-xue-jie-ti-by-yhhzw/

class Solution {
    public int[] plusOne(int[] digits) {
        for(int i=digits.length-1;i>-1;i--)
        {
            digits[i]++;
            digits[i]=digits[i]%10;
            if(digits[i]!=0) return digits;
        }
        digits=new int[digits.length+1]; //如果是更特别的情况长度+1
        digits[0]=1;//第一个是1,后面全是0
        return digits;
    }
}

第1题:两数之和

给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。
你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。

示例:

给定 nums = [2, 7, 11, 15], target = 9
因为 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]

解题思路:可以暴力法直接遍历,这里用哈希表

class Solution {
    public int[] twoSum(int[] nums, int target) {
        Map<Integer,Integer> map=new HashMap<Integer,Integer>();
        for(int i=0;i<nums.length;i++)
            map.put(nums[i],i);
        for(int i=0;i<nums.length;i++)
        {
           int com=target-nums[i];
            if(map.containsKey(com) && map.get(com)!=i) //如果是两个一样的保证是不是一个
            {
                return new int[]{i,map.get(com)};
            }
        }
        return new int[]{-1,-1};
        
    }
}

第15题:三数之和

给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有满足条件且不重复的三元组。注意:答案中不可以包含重复的三元组。
示例:

给定数组 nums = [-1, 0, 1, 2, -1, -4],
满足要求的三元组集合为:
[
  [-1, 0, 1],
  [-1, -1, 2]
]

解题思路: 排序,然后固定第一个,再用双指针判断后面,大于就右移,小于就左移,得到结果后再固定第二个,以此类推。

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
          Arrays.sort(nums);
          List<List<Integer>> res=new ArrayList();
          for(int i=0;i<nums.length;i++)
          {
              int target=0-nums[i]; //这个是双指针要判断的目标值
              int l=i+1;
              int r=nums.length-1;
              if(nums[i]>0) break;//如果大于0那么后面必定大于0直接结束
              if(i==0 || nums[i]!=nums[i-1]) //这个是去重
              {
                  while(l<r)
                  {
                      if(nums[l]+nums[r]==target)
                      {
                          res.add(Arrays.asList(nums[i],nums[l],nums[r]));
                          while(l<r && nums[l]==nums[l+1]) l++;//这个也是去重,下面的也是
                          while(l<r && nums[r]==nums[r-1]) r--;
                          l++;r--;
                      }else if(nums[l]+nums[r]>target)//说明需要右移
                       r--;
                       else
                       l++;
                  }
              }
          }
          return res;
    }
}

第6题:Z 字形变换

将一个给定字符串根据给定的行数,以从上往下、从左到右进行 Z 字形排列。比如输入字符串为 **“LEETCODEISHIRING” **行数为 3 时,排列如下:
L C I R
E T O E S I I G
E D H N

解题思路:
https://www.geekxh.com/1.0.%E6%95%B0%E7%BB%84%E7%B3%BB%E5%88%97/009.html#_01%E3%80%81%E9%A2%98%E7%9B%AE%E7%A4%BA%E4%BE%8B
https://leetcode-cn.com/problems/zigzag-conversion/solution/zzi-xing-bian-huan-by-jyd/
图解更清晰一点。
这里贴第二个的

class Solution {
    public String convert(String s, int numRows) {
          if(numRows<2) return s;
          List<StringBuilder> rows=new ArrayList<StringBuilder>();
          for(int i=0;i<numRows;i++) rows.add(new StringBuilder());
          int i=0,flag=-1;
          for(char c:s.toCharArray())
          {
              rows.get(i).append(c);
              if(i== 0 || i==numRows-1) flag=-flag;
              i+=flag;
          }
          StringBuilder res=new StringBuilder();
          for(StringBuilder row:rows) res.append(row);
          return res.toString();
    }
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值