zoukankan      html  css  js  c++  java
  • LeetCode中等题(一)

    题目一:

    给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。

    如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。

    您可以假设除了数字 0 之外,这两个数都不会以 0 开头。

    示例:

    输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
    输出:7 -> 0 -> 8
    原因:342 + 465 = 807

    分析:这道题目是一个链表题,对链表元素相加得出一个新的链表,那么怎么能实现链表元素的相加呢?其实这和我们实现两个数相加很类似,首先应该从个位数开始,如果之和大于10则将向前进一位。

    1、创建一个新的链表,用于返回最后相加和的结果,ListNode DummyNode=new ListNode(0);

    2、设置一些指向链表的节点,分别指向l1,l2,DummyNode, p1=l1,p2=l2,curr=DummyNode;

    3、开始遍历列表,进行求和,首先获取了l1,l2头节点的值,在进行相加  int x=(p1!=null)? p1.val:0;    int y=(p2!=null)? p2.val:0;   int sum=x+y+count;

    4、这里的难点在于求和后的结果超过10应该怎么办?我们应该将其记录下来,然后添加到下一次求和中,如上式的sum,记录的方式为:sum=sum/10,结果是0或者1;

    5、curr节点应该添加一个新的节点,并且存放所求得的和值,方式为curr.next=new ListCode(sum%10);

    6、将curr,p1,p2分别向后移动指针, curr=curr.next;    if(p1!=null) p1=p1.next;    if(p2!=null) p2=p2.next;

    7、如果在最后一轮循环中count大于1,这需要新创建一个节点  curr.next=new ListNode(count);

    8、返回链表DummyNode.next,因为第一个节点为0,无意义。

    具体实现过程:

    class Solution {
        public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
            
            ListNode DummyNode=new ListNode(0);
            ListNode p1=l1,p2=l2,curr=DummyNode;
            
            int count=0;    
            while(p1!=null||p2!=null)
            {
                int x=(p1!=null)? p1.val:0;
                int y=(p2!=null)? p2.val:0;
                int sum=x+y+count;
                count=sum/10;
                
                curr.next=new ListNode(sum%10);
                curr=curr.next;
                if(p1!=null) p1=p1.next;
                if(p2!=null) p2=p2.next;
            }
            
            if(count>0)
                curr.next=new ListNode(count);
            
            return DummyNode.next;
        }
    }

    题目二:

    给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。

    示例 1:

    输入: "abcabcbb"
    输出: 3
    解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。

    方法一:暴力法

    1、获得字符串长度,用二次循环直接遍历所有的可能性 for(int i=0; i<s.lenght;i++) for(int j=i+1;j<s.lenght;j++)

    2、获取所有字符串长度的最大值,ans=Math.max(ans,j-i)

    3、这里最主要的一部是获取字符串长度的比较,首先设置一个集合Set<Character> set=new HashSet<>();

    4、将字符串s,i,j的位置传入判断函数,获取传入的值Character ch=s.CharAt(i),获取索引i的值;

    5、判断ch值是否重复,if(set.contain(ch)) return false,set.add(ch);

    6、返回true;

    具体代码:

    class Solution {
        public int lengthOfLongestSubstring(String s) {
            
            int n=s.length();
            int ans=0;
            
            for(int i=0;i<n;i++)
                for(int j=i+1;j<=n;j++)
                {
                    if(JugleFun(s,i,j)) ans=Math.max(ans, j-i);
                }
            
            return ans;
        }
        
        public boolean JugleFun(String s,int start,int end)
        {
            Set<Character> set=new HashSet<>();
            
            for(int i=start;i<end;i++)
            {
                Character ch=s.charAt(i);
                if(set.contains(ch)) return false;
                set.add(ch);
            }
            
            return true;
        }
    }

    方法二:滑动窗口

    1、使用i=0,j=0两个值向后逐个滑动

    2、主要的思想:如果遍历过字符串为不重复子串,就没必要再去重复判断,如果1234561,i=1,j=1,直接从i=2和j=1进行判断;

    3、if(!set.contain(s.charAt(j))),set.add(s.char(j++))  否则set.remove(s.charAt(i++));

    具体代码:

    class Solution {
        public int lengthOfLongestSubstring(String s) {
            
            int n=s.length();
            int i=0,j=0,ans=0;
            Set<Character> set=new HashSet<>();
            
            while(i<n&&j<n)
            {
                if(!set.contains(s.charAt(j)))
                {
                    set.add(s.charAt(j++));
                    ans=Math.max(ans, j-i);
                }
                else {
                    set.remove(s.charAt(i++));
                }
            }
            
            return ans;
        }
    }

    题目三:

    给定一个只包括 '(',')','{','}','[',']' 的字符串,判断字符串是否有效。

    有效字符串需满足:

    左括号必须用相同类型的右括号闭合。
    左括号必须以正确的顺序闭合。
    注意空字符串可被认为是有效字符串。

    示例 1:

    输入: "()"
    输出: true

    分析:

    1、字符的两两匹配问题,先将其放入哈希表中,HashMap<Character,Character> hashmap=new HashMap<>();

    2、在构造函数中进行初始化,hashmap.put(')','(');

    3、应该使用栈数据结构,将放入的元素和栈顶元素对比,Stack<Character> stack=new Stack<>(),获取串元素:k=s.CharAt(i);

    4、如果是哈希表中的键,将进行对比,否则直接压栈,if(hashmap.containKey(c)), 获取栈顶元素:Character topElem=stack.empty()? '#':stack.pop();

    5、比较栈顶元素和要入栈的元素是否相同,if(topElem!=hashmap.get(c))

    6、返回栈是否为空,return stack.empty();

    具体代码:

    class Solution {
        
        private HashMap<Character, Character> hashMap=new HashMap<Character,Character>();
        
        public Solution()
        {
            hashMap.put(')', '(');
            hashMap.put('}', '{');
            hashMap.put(']', '[');
        }
        
        public boolean isValid(String s) {
            
            Stack<Character> stack=new Stack<>();
            
            for(int i=0;i<s.length();i++)
            {
                char c=s.charAt(i);
                
                if(hashMap.containsKey(c))
                {
                    Character topEle=stack.empty()? '#':stack.pop();
                    
                    if(topEle!=hashMap.get(c))
                        return false;
                }
                
                else {
                    stack.push(c);
                }
            }        
            return stack.empty();
        }
    }

    题目四:

    给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。

    示例:

    给定一个链表: 1->2->3->4->5, 和 n = 2.

    当删除了倒数第二个节点后,链表变为 1->2->3->5.

    方法一:

    1、删除倒数第n个节点,先应该遍历出链表的长度,然后用lenght=length-n;

    2、判断链表长度定位到删除的位置,if(lenght>0) curr=curr.next;

    3、需要设置两个节点,一个用来遍历curr,另一个指向头结点,ListNode dummy=new ListNode;

    4、返回dummy.next;

    具体代码:

    class Solution {
        public ListNode removeNthFromEnd(ListNode head, int n) {
            
            ListNode curr=head;
            ListNode dummy=new ListNode(0);
            dummy.next=head;
            int count=0;
            
            while(curr!=null)
            {
                count++;
                curr=curr.next;            
            }
    count
    -=n; curr=dummy; while(count>0) { count--; curr=curr.next; } curr.next=curr.next.next; return dummy.next; } }

    方法二:

    分析:

    1、采用双指针实现first指针先执行n步,然后second指针开始执行

    2、直到first为空,停止执行second;

    3、将second指针指向下一个节点second.next=second.next.next;

    4、开始设置哑结点指向头结点,first和second都指向dummy

    具体代码:

    class Solution {
        public ListNode removeNthFromEnd(ListNode head, int n) {
            
            ListNode dummy=new ListNode(0);
            dummy.next=head;
            ListNode first=dummy;
            ListNode second=dummy;
            
            for(int i=1;i<=n+1;i++)
            {
                first=first.next;
            }
            
            while(first!=null)
            {
                first=first.next;
                second=second.next;
            }
            
            second.next=second.next.next;
            
            return dummy.next;
        }
    }

    题目五:

    给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。

    示例 1:

    输入: "babad"
    输出: "bab"
    注意: "aba" 也是一个有效答案。

    方法一:暴力法

    判断字符串中的回文,并将最大的回文串返回

    1、将所有的字符串进行遍历,判断每个字符串是否为回文;

    2、可以另外设置一个函数进行判断,判断字符串的第一位和最后一位是否相同即可,即if(s.charAt(i)==s.charAt(lenght-i-1))

    3、设置返回的字符串为ans=" ";如果字符串为回文,那么返回最大的字符串,ma=0;if(str.lengt>0),ans=str,ma=Math.max(max,str.lenght);

    4、返回length;

    class Solution {
        public String longestPalindrome(String s) {
            
            String ans="";
            int ma=0;
            
            for(int i=0;i<s.length();i++)
                for(int j=i+1;j<=s.length();j++)
                {     
                    String str=s.substring(i,j);
                    if(isHuiWei(str)&&str.length()>ma)
                    {
                        ans=s.substring(i,j);
                        ma=Math.max(ma, ans.length());
                    }
                }
            return ans;
        }
        
        public boolean isHuiWei(String s)
        {
            
            int len=s.length();
            for(int i=0;i<len/2;i++)
            {
                if(s.charAt(i)!=s.charAt(len-i-1))
                {
                    return false;
                }
            }       
            return true;
        }
        
    }

    方法二:动态规划

    class Solution {
        public String longestPalindrome(String s) {
            
            int len=s.length();
            if(len<=1)
                return s;
            
            int longpa=1;
            String string=s.substring(0,1);
            boolean[][] dp=new boolean[len][len];
            
            for(int r=1;r<len;r++)
                for(int l=0;l<r;l++)
                {
                    if(s.charAt(l)==s.charAt(r)&&(r-l<=2||dp[l+1][r-1]))
                    {
                        dp[l][r]=true;
                        if(r-l+1>longpa)
                        {
                            longpa=r-l+1;
                            string=s.substring(l,r+1);
                        }
                    }            
                }
            return string;
        }
    }

    题目六:

    一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。

    机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。

    问总共有多少条不同的路径?

    方法一:

    1、递归算法递归出口:if(m==1||n==1) return 1;

    2、返回结果:ans=uniquePath(m-1,n)+uniquePath(m,n-1);

    具体代码:

    class Solution {
        public int uniquePaths(int m, int n) {
            
            if(m==1||n==1)
                return 1;
            
            int ans=uniquePaths(m-1, n)+uniquePaths(m, n-1);
            
            return ans;
        }
    }

    方法二:

    1、动态规划,状态方程:dp[i][j]=dp[i-1][j]+dp[i][j-1];

    2、状态初始化:dp[i][0]=1,dp[0][j]=1;

    3、返回最后的结果,return dp[m-1][n-1];

    具体代码:

    class Solution {
        public int uniquePaths(int m, int n) {
            
            int[][] dp=new int[m][n];
            
            for(int i=1;i<=m;i++) dp[i][0]=1;
            for(int i=1;i<=n;i++) dp[0][i]=1;
            for(int i=1;i<=m;i++)
                for(int j=1;j<=m;j++)
                {
                    dp[i][j]=dp[i-1][j]+dp[i][j-1];
                }
            return dp[m-1][n-1];
        }
    }

    题目七:

    给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。

    candidates 中的数字可以无限制重复被选取。

    说明:

    所有数字(包括 target)都是正整数。
    解集不能包含重复的组合。 
    示例 1:

    输入: candidates = [2,3,6,7], target = 7,
    所求解集为:
    [
    [7],
    [2,2,3]
    ]

    方法:

    回溯加递归

    具体代码:

    class Solution {
        
        private int[] candidates;
        private List<List<Integer>> res=new ArrayList<>();
        private int len;
        
        public List<List<Integer>> combinationSum(int[] candidates, int target) {
            
            int len=candidates.length;
            if(len==0)
                return res;
            
            Arrays.sort(candidates);
            this.len=len;
            this.candidates=candidates;
            
            findCombinationSum(target,0,new Stack<>());
            return res;
        }
        
        public void findCombinationSum(int target,int start,Stack<Integer> stack)
        {
            if(target==0)
            {
                res.add(new ArrayList<>(stack));
                return;
            }
            
            for(int i=start;i<len&&(target-candidates[i])>=0;i++)
            {
                stack.add(candidates[i]);
                findCombinationSum(target-candidates[i], i, stack);
                stack.pop();
            }
        }
    }

    题目八:

    给定一个非负整数数组,你最初位于数组的第一个位置。

    数组中的每个元素代表你在该位置可以跳跃的最大长度。

    判断你是否能够到达最后一个位置。

    示例 1:

    输入: [2,3,1,1,4]
    输出: true
    解释: 从位置 0 到 1 跳 1 步, 然后跳 3 步到达最后一个位置。

    方法一:

    1、递归算法,我们想要实现是否满足路径;

    2、创建一个函数实现是个可以从一个位置,从位置0开始,是否能够到达最后一个位置;

    3、实现递归,第二个位置是否能够实现到达最后一个位置; 将所有的可能性都列举出来,位置1可能到达的位置;

    4、fasterPos=Math.min(positon+nums[position]),进行循环fasterPos次;

    具体代码:

    class Solution {
        public boolean canJump(int[] nums) {
            
            return FromCanJump(0, nums);
        }
        
        public boolean FromCanJump(int position,int[] nums)
        {
            int len=nums.length-1;
            if(position==len)
                return true;
            
            int FasterDistance=Math.min(position+nums[position], len);
            for(int nextPostion=position+1;nextPostion<=FasterDistance;nextPostion++)
            {
                if(FromCanJump(nextPostion, nums))
                    return true;
            }
            
            return false;
        }
    }

    方法二:

    将递归出来的元素保存在一个数组中

    具体代码:

    enum Index
    {GOOD,BAD,UNKOWN}
    
    class Solution {
        Index[] mono;
        
        public boolean canJump(int[] nums) {
            mono=new Index[nums.length];
            
            for(int i=0;i<mono.length;i++)
            {
                mono[i]=Index.UNKOWN;
            }
            mono[mono.length-1]=Index.GOOD;
            
            return canJumpPosition(0,nums);
        }
        
        public boolean canJumpPosition(int position, int[] nums)
        {
            if(mono[position]!=Index.UNKOWN)
            {
                return mono[position]==Index.GOOD?true:false;
            }
            
            int furthestJump = Math.min(position + nums[position], nums.length - 1);
            for (int nextPosition = position + 1; nextPosition <= furthestJump; nextPosition++) {
                if (canJumpPosition(nextPosition, nums)) {
                    mono[position] = Index.GOOD;
                    return true;
                }
            }
            
            mono[position] = Index.BAD;
            return false;
        }
    }

    题目九:

    给定一个二叉树,返回其按层次遍历的节点值。 (即逐层地,从左到右访问所有节点)。

    例如:
    给定二叉树: [3,9,20,null,null,15,7],

    3
    /
    9 20
    /
    15 7

    方法一:

    1、递归,二叉树层次遍历用递归可以实现

    2、不过需要做一些简单的设置,并不能原函数上进行递归,原函数只给定了根节点;

    3、还需要另外一个参数,层level,对这个函数进行递归

    4、if(levels.size()==level) 增加一个数组,levels.add(new Arraylist());

    5、添加元素到数组中,levels.get(level).add(node.val);

    具体代码:

    class Solution {
        
        List<List<Integer>> levels=new ArrayList<>();
        
        public List<List<Integer>> levelOrder(TreeNode root) {
            
            if(root==null) return levels;
            Creatlevel(root, 0);
            
            return levels;
        }
        
        public List<List<Integer>> Creatlevel(TreeNode node,int level)
        {
            if(levels.size()==level)
                levels.add(new ArrayList<>());
            
            levels.get(level).add(node.val);
            
            if(node.left!=null)
                Creatlevel(node.left, level+1);
            if(node.right!=null)
                Creatlevel(node.right, level+1);
            
            return levels;
        }
    }

    方法二:

    队列

    具体代码:

    class Solution {
            
        public List<List<Integer>> levelOrder(TreeNode root) {
            
            List<List<Integer>> levels=new ArrayList<>();
            if(root==null) return levels;
            
            Queue<TreeNode> queue=new LinkedList<TreeNode>();
            queue.add(root);
            
            int level=0;
            while(!queue.isEmpty())
            {
                levels.add(new ArrayList<>());
                int level_size=levels.size();
                
                for(int i=0;i<level_size;i++)
                {
                    TreeNode node=queue.remove();
                    levels.get(level).add(node.val);
                    
                    if (node.left != null) queue.add(node.left);
                    if (node.right != null) queue.add(node.right);
    
                }            
                level++;
            }
        }
    }

    题目十:

    给定一个链表,旋转链表,将链表每个节点向右移动 k 个位置,其中 k 是非负数。

    示例 1:

    输入: 1->2->3->4->5->NULL, k = 2
    输出: 4->5->1->2->3->NULL
    解释:
    向右旋转 1 步: 5->1->2->3->4->NULL
    向右旋转 2 步: 4->5->1->2->3->NULL

    方法:

    1、链表的移动,遍历整个链表,先找到尾节点的值,并把尾结点指向head使得链表构成一个环

    2、for(int n=1;old_tail!=null;n++) old_tail=old_tail.next,这里需要记录一下整个链表的长度;

    3、定义一个新的尾结点new_tail,for(int i=0;i<n-k%n-1;i++) new_tail=new_tail.next,这里的循环条件满足k>n;

    4、定义一个新的头节点new_head=new_tail.next;new_tail.next=null;

    5、返回new_head

    具体代码:

    class Solution {
        public ListNode rotateRight(ListNode head, int k) {
            
            if(head==null) return null;
            if(head.next==null) return head;
            
            ListNode old_tail=head;
            int n;
            for(n=1;old_tail.next!=null;n++)
            {
                old_tail=old_tail.next;
            }
            old_tail.next=head;
            
            ListNode new_tail=head;
            for(int i=0;i<n-k%n-1;i++)
            {
                new_tail=new_tail.next;
            }
            
            ListNode new_head=new_tail.next;
            new_tail.next=null;
            
            return new_head;
        }
    }
  • 相关阅读:
    [iOS]为什么不要在init初始化方法里调用self.view
    [iOS]ARC和MRC下混编
    CollectionView的基础代码
    关于ios项目中加入webp格式的图片
    【音频】远程链接音频播放(AVPlayer)
    iOS微信支付回调和iOS9系统左上角返回的冲突解决
    【转载】iOS开发经验总结
    【转载】iOS超全开源框架、项目和学习资料汇总(4)数据库、缓存处理、图像浏览、摄像照相视频音频篇
    【转载】3分钟实现iOS语言本地化/国际化(图文详解)
    微信小程序推荐网站
  • 原文地址:https://www.cnblogs.com/Optimism/p/11272814.html
Copyright © 2011-2022 走看看