【Android春招每日一练】(九) 剑指4题+Android基础

【Android春招每日一练】(九) 剑指4题+Android基础,第1张

【Android春招每日一练】(九) 剑指4题+Android基础

文章目录

概览剑指offer

1.33 二叉树中和为某一值的路径1.34 复杂链表的复制1.35 二叉搜索树与双向链表1.36 序列化二叉树 Android基础

Fragment 总结

概览

剑指offer:二叉树中和为某一值的路径、复杂链表的复制、二叉搜索树与双向链表、序列化二叉树
Android基础:Fragment

剑指offer 1.33 二叉树中和为某一值的路径

给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。

叶子节点 是指没有子节点的节点。

//DFS
//先序遍历,记录从根节点到当前节点的路径,比较target值
class Solution {
    linkedList path = new linkedList<>();
    linkedList> res = new linkedList<>();
    public List> pathSum(TreeNode root, int target) {
        recur(root,target);
        return res;
    }

    void recur(TreeNode root,int target){
        if(root == null) return;
        path.add(root.val);
        target -= root.val;
        if(target == 0 && root.left == null && root.right == null)
            res.add(new linkedList(path));	//需要new一个新的path,否则path加入res中也会随时变化
        recur(root.left,target);
        recur(root.right,target);
        path.removeLast();			//从path移除当前节点
    }
}
1.34 复杂链表的复制

请实现 copyRandomList 函数,复制一个复杂链表。在复杂链表中,每个节点除了有一个 next 指针指向下一个节点,还有一个 random 指针指向链表中的任意节点或者 null。

示例 1:
输入:head = [[7,null],[13,0],[11,4],[10,2],[1,0]]
输出:[[7,null],[13,0],[11,4],[10,2],[1,0]]
//本题难点在于新建链表时random指向节点无法确定
//使用一个HashMap存储节点,构建random时直接去HashMap中查找;
class Solution {
    public Node copyRandomList(Node head) {
        if(head == null) return null;
        Node cur = head;
        Map map = new HashMap<>();
        // 复制各节点,并建立 “原节点 -> 新节点” 的 Map 映射
        while(cur != null) {
            map.put(cur, new Node(cur.val));
            cur = cur.next;
        }
        cur = head;
        // 构建新链表的 next 和 random 指向
        while(cur != null) {
            map.get(cur).next = map.get(cur.next);
            map.get(cur).random = map.get(cur.random);
            cur = cur.next;
        }
        // 返回新链表的头节点
        return map.get(head);
    }
}
1.35 二叉搜索树与双向链表

输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的循环双向链表。要求不能创建任何新的节点,只能调整树中节点指针的指向。

//dfs
//根据二叉搜索树的中序遍历为递增序列,在中序遍历时更改左右指针。
class Solution {
    Node pre,head;
    public Node treeToDoublyList(Node root) {
        if(root == null) return null;
        dfs(root);
        head.left = pre;
        pre.right = head;
        return head;
    }

    void dfs(Node cur){
        if(cur == null) return;
        dfs(cur.left);
        if(pre == null) head = cur;	//已经到达头节点
        else pre.right = cur;		//建立指针
        cur.left = pre;				//可以与上面语句交换或者合并
        pre = cur;					//记录前驱节点
        dfs(cur.right);
    }
}
1.36 序列化二叉树

请实现两个函数,分别用来序列化和反序列化二叉树。

你需要设计一个算法来实现二叉树的序列化与反序列化。这里不限定你的序列 / 反序列化算法执行逻辑,你只需要保证一个二叉树可以被序列化为一个字符串并且将这个字符串反序列化为原始的树结构。

//BFS
//DFS、前序、中序、后序都不能反序列化,使用层次遍历,并且保存null节点即可
public class Codec {

    // Encodes a tree to a single string.
    public String serialize(TreeNode root) {
        if(root == null) return "[]";
        Queue queue = new linkedList<>();
        StringBuilder res = new StringBuilder("[");
        queue.add(root);
        while(!queue.isEmpty()){
            TreeNode tNode = queue.poll();
            if(tNode != null){
                res.append(tNode.val + ",");
                queue.add(tNode.left);
                queue.add(tNode.right);
            }else{
                res.append("null,");
            } 
        }
        res.deleteCharAt(res.length() - 1); //去掉最后一个逗号
        res.append("]");
        return res.toString();
    }

    // Decodes your encoded data to tree.
    public TreeNode deserialize(String data) {
        if(data.equals("[]")) return null;
        String[] vals = data.substring(1, data.length() - 1).split(",");
        TreeNode root = new TreeNode(Integer.parseInt(vals[0]));
        Queue queue = new linkedList<>() {{ add(root); }};
        int i = 1;
        while(!queue.isEmpty()) {
            TreeNode node = queue.poll();
            if(!vals[i].equals("null")) {
                node.left = new TreeNode(Integer.parseInt(vals[i]));
                queue.add(node.left);
            }
            i++;
            if(!vals[i].equals("null")) {
                node.right = new TreeNode(Integer.parseInt(vals[i]));
                queue.add(node.right);
            }
            i++;
        }
        return root;
    }
}
Android基础 Fragment

生命周期

切换Fragment方式

1.准备好Fragment,然后再Activity中实例化,v4包的Fragment是通过getSupportFragmentManager()方法新建Fragment管理器对象;

2.然后通过Fragment管理器对象调用beginTransaction()方法,实例化FragmentTransaction对象,即事务 ;

3.调用FragmentTransaction对象的replace方法;

4.最后调用commit方法.

    public void  replaceFragment(Fragment fragment){
        FragmentManager fragmentManager = getSupportFragmentManager();
        FragmentTransaction transaction = fragmentManager.beginTransaction();
        transaction.replace(R.id.main_activity_content,fragment);
        transaction.addToBackStack(null);
        transaction.commit();
    }

Fragment的回退栈

Fragment的回退栈是用来保存每一次Fragment事务发生的变化 如果你将Fragment任务添加到回退栈,当用户点击后退按钮时,将看到上一次的保存的Fragment。一旦Fragment完全从后退栈中d出,用户再次点击后退键,则退出当前Activity .

Fragment的点击事件里写的是replace方法,相当于remove和add的合体,并且如果不添加事务到回退栈,前一个Fragment实例会被销毁。我们调用tx.addToBackStack(null)将当前的事务添加到了回退栈,所以FragmentOne实例不会被销毁,但是视图层次依然会被销毁,即会调用onDestoryView和onCreateView。

如果不希望视图重绘,可以不调用replace,使用hide先隐藏了当前的Fragment,然后添加 FragmentThree的实例,最后将事务添加到回退栈。

FragmentTransaction tx = fm.beginTransaction(); 
tx.hide(this); 
tx.add(R.id.id_content , fThree, "THREE");
//tx.replace(R.id.id_content, fThree, "THREE");
tx.addToBackStack(null); tx.commit();

Fragment与Activity之间的通信

Bundle方式:新建fragment自带(最好的例子)

    // TODO: Rename parameter arguments, choose names that match
    // the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
    private static final String ARG_PARAM1 = "param1";
    private static final String ARG_PARAM2 = "param2";

    // TODO: Rename and change types of parameters
    private String mParam1;
    private String mParam2;

    public BlankFragment() {
        // Required empty public constructor
    }

    public static BlankFragment newInstance(String param1, String param2) {
        BlankFragment fragment = new BlankFragment();
        Bundle args = new Bundle();
        args.putString(ARG_PARAM1, param1);
        args.putString(ARG_PARAM2, param2);
        fragment.setArguments(args);
        return fragment;
    }

接口回调方式

//Fragment.java
...
    public interface ICallback{
        void sendMsg(String string);
    }

    public void sendMessage(ICallback callback){
        callback.sendMsg("123");
    }
...
//Activity.java
fragment.sendMessage(new BlankFragment.ICallback() {
	@Override
	public void sendMsg(String string) {
		System.out.println(string);
	}
});

运行时保存数据

当屏幕发生旋转,Activity发生重新启动,默认的Activity中的Fragment也会跟着Activity重新创建;这样造成当旋转的时候,本身存在的Fragment会重新启动,然后当执行Activity的onCreate时,又会再次实例化一个新的Fragment。

通过检查onCreate的参数Bundle savedInstanceState就可以判断,当前是否发生Activity的重新创建 默认的savedInstanceState会存储一些数据,包括Fragment的实例;所以,只需要在onCreate时判断只有在savedInstanceState==null时,才进行创建Fragment实例 。

Fragment也有onSaveInstanceState的方法,在此方法中进行保存数据,然后在onCreate或者onCreateView或者onActivityCreated进行恢复。

总结

1.Android的各种机制应该结合源码多加理解;
2.今天比较忙所以所学时间不多。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/5712817.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存